338 Stimmen

Wie testet man die Gleichheit von Zeichenfolgen und Ganzzahlen und kombiniert sie mit den logischen && und || Operatoren in bash?

Ich habe ein paar Variablen und möchte die folgende Bedingung überprüfen (in Worten beschrieben, dann mein fehlgeschlagener Versuch beim Bash-Skripten):

if varA GLEICH 1 UND (varB GLEICH "t1" ODER varB GLEICH "t2") dann 

etwas tun

fertig.

Und bei meinem fehlgeschlagenen Versuch kam ich auf:

if (($varA == 1)) && ((($varB == "t1")) || (($varC == "t2"))); 
  dann
    scale=0.05
  fi

855voto

Was du geschrieben hast, funktioniert tatsächlich fast (es würde funktionieren, wenn alle Variablen Zahlen wären), aber es ist überhaupt nicht auf idiomatische Weise.

  • (…) Klammern zeigen eine Unter-Shell an. Was sich darin befindet, ist kein Ausdruck wie in vielen anderen Sprachen. Es handelt sich um eine Liste von Befehlen (genau wie außerhalb der Klammern). Diese Befehle werden in einem separaten Unterprozess ausgeführt, sodass alle Umleitungen, Zuweisungen usw., die innerhalb der Klammern ausgeführt werden, keine Auswirkungen außerhalb der Klammern haben.
    • Mit einem führenden Dollarzeichen ist $(…) eine Befehls-Substitution: Es gibt einen Befehl innerhalb der Klammern, und die Ausgabe des Befehls wird als Teil der Befehlszeile verwendet (nach zusätzlichen Erweiterungen, es sei denn, die Substitution befindet sich zwischen doppelten Anführungszeichen, aber das ist eine andere Geschichte).
  • { … } Klammern sind wie Klammern, da sie Befehle gruppieren, aber sie beeinflussen nur die Analyse, nicht die Gruppierung. Das Programm x=2; { x=4; }; echo $x gibt 4 aus, während x=2; (x=4); echo $x 2 ausgibt. (Außerdem erfordern Klammern Leerzeichen um sie herum und ein Semikolon vor dem Schließen, während Klammern das nicht erfordern. Das ist nur eine Syntax-Eigenheit.)
    • Mit einem führenden Dollarzeichen lautet die Syntax ${VAR} Parameter-Expansion, die den Wert einer Variablen erweitert, mit möglichen zusätzlichen Transformationen.
  • ((…)) doppelte Klammern umgeben eine arithmetische Anweisung, das heißt, eine Berechnung von Ganzzahlen, mit einer Syntax, die anderen Programmiersprachen ähnelt. Diese Syntax wird hauptsächlich für Zuweisungen und Bedingungen verwendet.
    • Dieselbe Syntax wird in arithmetischen Ausdrücken $((…)) verwendet, die den ganzzahligen Wert des Ausdrucks erweitern.
  • [[ … ]] doppelte eckige Klammern umgeben Bedingungsausdrücke. Bedingungsausdrücke basieren hauptsächlich auf Operatoren wie -n $variable zum Testen, ob eine Variable leer ist, und -e $file zum Testen, ob eine Datei existiert. Es gibt auch Zeichenfolgen-Gleichheitsoperatoren: "$string1" == "$string2" (beachte, dass die rechte Seite ein Muster ist, z. B. [[ $foo == a* ]] testet, ob $foo mit a beginnt, während [[ $foo == "a*" ]] testet, ob $foo genau a* ist), und die vertrauten !, && und || Operatoren zur Negation, Konjunktion und Disjunktion sowie Klammern zur Gruppierung. Beachte, dass du um jeden Operator herum ein Leerzeichen benötigst (z. B. [[ "$x" == "$y" ]], nicht [[ "$x"=="$y" ]]), und ein Leerzeichen oder ein Zeichen wie ; sowohl innerhalb als auch außerhalb der Klammern benötigst (z. B. [[ -n $foo ]], nicht [[-n $foo]]).
  • [ … ] einfache eckige Klammern sind eine alternative Form von Bedingungsausdrücken mit mehr Eigenheiten (aber älter und portabler). Schreibe vorerst keine, fang an, dich darüber Gedanken zu machen, wenn du Skripte findest, die sie enthalten.

Das ist die idiomatische Art, deinen Test in bash zu schreiben:

if [[ $varA == 1 && ($varB == "t1" || $varC == "t2") ]]; then

Wenn du die Portabilität zu anderen Shells benötigst, wäre dies der Weg:

if [ "$varA" = 1 ] && { [ "$varB" = "t1" ] || [ "$varC" = "t2" ]; }; then

(beachte die zusätzlichen Anführungszeichen und die separaten Klammern um jeden einzelnen Test herum und die Verwendung des traditionellen = Operators anstelle der ksh/bash/zsh == Variante)

18 Stimmen

Es ist besser, == zu verwenden, um den Vergleich von der Variablenzuweisung zu unterscheiden (die auch = ist).

0 Stimmen

+1 @WillSheppard für die Erinnerung an den richtigen Stil. Gilles, brauchst du nicht ein Semikolon nach deiner schließenden geschweiften Klammer und vor "then"? Ich dachte immer, if, then, else und fi könnten nicht in derselben Zeile stehen... Wie in: if [ "$varA" = 1 ] && { [ "$varB" = "t1" ] || [ "$varC" = "t2" ]; }; then

0 Stimmen

Backquotes (`…`) sind eine alte Form der Befehlssubstitution, mit einigen Unterschieden: In dieser Form behält der Backslash seine wörtliche Bedeutung bei, außer wenn er von $, ` oder \ gefolgt wird, und das erste Backquote, das nicht von einem Backslash vorangestellt ist, beendet die Befehlssubstitution; während in der Form $(…) alle Zeichen zwischen den Klammern den Befehl ausmachen, werden keine davon speziell behandelt.

46voto

matchew Punkte 18232

Es ist sehr nahe.

if [[ $varA -eq 1 ]] && [[ $varB == 't1' || $varC == 't2' ]];
  then
    scale=0.05
  fi

sollte funktionieren.

Zerlegen wir es,

[[ $varA -eq 1 ]]

ist ein Integer-Vergleich, während

$varB == 't1'

ein String-Vergleich ist. Ansonsten gruppiere ich die Vergleiche nur ordnungsgemäß.

Doppelte eckige Klammern grenzen einen Bedingungsausdruck ein. Und ich finde das Folgende zu einem guten Lesestoff zum Thema: ["(IBM) Demystify test, [, [[, ((, und if-then-else"](http://www.ibm.com/developerworks/library/l-bash-test/index.html)

0 Stimmen

Nur zur Sicherheit: Das Zitieren in 't1' ist unnötig, oder? Weil im Gegensatz zu arithmetischen Anweisungen in doppelten Klammern, wo t1 eine Variable wäre, ist t1 in einem bedingten Ausdruck in doppelten Klammern nur ein Literalstring. D.h., [[ $varB == 't1' ]] ist genau dasselbe wie [[ $varB == t1 ]], oder?

12voto

J.P. Tosoni Punkte 445

Eine sehr portable Version (auch für das veraltete Bourne-Shell):

if [ "$varA" = 1 -a \( "$varB" = "t1" -o "$varB" = "t2" \) ]
then    irgendetwas tun
fi

Es hat die zusätzliche Eigenschaft, dass nur höchstens ein Unterprozess ausgeführt wird (der Prozess [), unabhängig von der Shell-Art.

Ersetze = durch -eq, wenn die Variablen numerische Werte enthalten, z.B.

  • 3 -eq 03 ist wahr, aber
  • 3 = 03 ist falsch. (Zeichenfolgenvergleich)

0 Stimmen

Ehrliche Frage: Warum ist die Portabilität zum Legacy-Bourne-Shell wichtig? Welche sind die Anwendungsfälle für sh, bei denen bash nicht ausreicht?

1 Stimmen

@András: Es gibt viele Varianten der Shell, alle außer csh leiten von der Bourne-Shell ab, nur wenige sind bash-kompatibel. Zum Beispiel ist die Openwrt-Shell "ash", die viele bash-Eigenschaften vermissen lässt. ksh, dash werden viel verwendet, sind aber nicht vollständig bash-kompatibel. Kompatibilität ist ein Problem für die Programmierer, um zu vermeiden, jedes Mal, wenn sie zu einem anderen Job wechseln, eine neue Shell-Spezifik zu erlernen. Nur meine 2 Cent.

9voto

tlc Punkte 81

Hier ist der Code für die Kurzversion der if-then-else Anweisung:

( [ $a -eq 1 ] || [ $b -eq 2 ] ) && echo "ok" || echo "nok"

Achten Sie auf Folgendes:

  1. || und && Operatoren innerhalb der if Bedingung (d.h. zwischen runden Klammern) sind logische Operatoren (oder/und)

  2. || und && Operatoren außerhalb der if Bedingung bedeuten then/else

Praktisch gesehen sagt die Anweisung:

wenn (a=1 oder b=2) dann "ok" sonst "nok"

0 Stimmen

Klammern ( ... ) erstellen eine Unter-Shell. Möglicherweise möchten Sie stattdessen geschweifte Klammern { ... } verwenden. Jeder Zustand, der in einer Unter-Shell erstellt wird, ist für den Aufrufer nicht sichtbar.

0 Stimmen

Sollte das so gelesen werden, "&& und || Operanden außerhalb der if-Bedingung bedeuten dann/sonst" ...?

-1voto

AlikElzin-kilaka Punkte 31624
if ([ $NUM1 == 1 ] || [ $NUM2 == 1 ]) && [ -z "$STR" ]
then
    echo STR ist leer, sollte aber einen Wert haben.
fi

1 Stimmen

Können Sie mir bitte sagen, wozu das -z-Flag in Bash verwendet wird?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X