Mehrere logische Operatoren ((A || B) & & C) und “ Syntaxfehler in der Nähe eines unerwarteten Tokens ”

Ich arbeite mit Bash 3 und versuche es bilden eine Bedingung. In C / C ++ ist es ganz einfach: ((A || B) && C). In Bash stellt sich heraus, dass dies nicht der Fall ist (ich denke, die Git-Autoren müssen diesen Code beigesteuert haben, bevor sie sich anderen Bestrebungen zugewandt haben).

Dies funktioniert nicht. Beachten Sie, dass <0 or 1> kein Zeichenfolgenliteral ist. es bedeutet eine 0 oder 1 (kommt im Allgemeinen von grep -i).

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eqe "0" ]; then ... fi 

Es ergibt sich:

line 322: syntax error near unexpected token `[[" 

Ich habe dann versucht:

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ ([ "$A" -eq "0" ]) || ([ "$B" -ne "0" ]) ] && [ "$C" -eq "0" ]; then ... fi 

es ergibt sich:

line 322: syntax error near unexpected token `[[" 

Ein Teil des Problems besteht darin, dass Suchergebnisse triviale Beispiele sind und nicht die komplexeren Beispiele mit zusammengesetzten Bedingungen.

Wie führe ich eine einfache ((A || B) && C) in Bash?


Ich bin bereit, es einfach abzuwickeln und dieselben Befehle in mehreren Blöcken zu wiederholen:

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ "$A" -eq "0" ] && [ "$C" -eq "0" ]; then ... elif [ "$B" -ne "0" ] && [ "$C" -eq "0" ]; then ... fi 

Antwort

Die Syntax von bash ist nicht C-ähnlich, auch wenn ein kleiner Teil davon von C inspiriert ist. Sie können nicht einfach versuchen, C-Code zu schreiben und erwarten, dass er funktioniert.

Der Hauptpunkt einer Shell besteht darin, Befehle auszuführen. Der Open-Bracket-Befehl [ ist ein Befehl, der einen einzelnen Test¹ ausführt. Sie können es sogar als test schreiben (ohne die letzte schließende Klammer). Die Operatoren || und && sind Shell-Operatoren. Sie kombinieren Befehle und keine Tests.

Wenn Sie also

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ] 

schreiben, wird dies als

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ] 

analysiert ist dasselbe wie

test [ "$A" -eq "0" || test "$B" -ne "0" ] && test "$C" -eq "0" 

Beachten Sie die unausgeglichenen Klammern? Ja, das ist nicht gut. Ihr Versuch mit Klammern hat das gleiche Problem: falsche Klammern.

Die Syntax zum Gruppieren von Befehlen lautet geschweifte Klammern. Die Art und Weise, wie Klammern analysiert werden, erfordert einen vollständigen Befehl vor ihnen. Sie müssen den Befehl in den Klammern daher mit einem Zeilenumbruch oder einem Semikolon beenden.

if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then … 

Dort „s eine alternative Möglichkeit, doppelte Klammern zu verwenden. Im Gegensatz zu einfachen Klammern sind doppelte Klammern eine spezielle Shell-Syntax. Sie begrenzen bedingte Ausdrücke . In doppelten Klammern können Sie Klammern und Operatoren wie && und || verwenden. Da die doppelten Klammern Shell-Syntax sind, weiß die Shell, dass diese Operatoren, wenn sie sich in Klammern befinden, „Teil der Syntax für bedingte Ausdrücke und nicht Teil der normalen Shell-Befehlssyntax sind.

if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then … 

Wenn alle Ihre Tests numerisch sind, gibt es noch einen anderen Weg, der artihmetische Ausdrücke abgrenzt. Arithmetische Ausdrücke führen Ganzzahlberechnungen mit einer sehr C-ähnlichen Syntax durch.

if (((A == 0 || B != 0) && C == 0)); then … 

Möglicherweise finden Sie meine Bash-Klammer Primer nützlich.

[ kann in normalem sh verwendet werden. [[ und (( sind spezifisch für bash (und ksh und zsh).

¹ Es kann auch Kombinieren Sie mehrere Tests mit booleschen Operatoren, aber dies ist umständlich zu verwenden und weist subtile Fallstricke auf, sodass ich es nicht erklären werde.

Kommentare

  • Danke Giles. Gilt das für Bash 2 bis Bash 4? Ich brauche etwas milde Portabilität, aber Kusalananda erwähnte, dass einige Dinge, die ich nicht tat, portabel sind (bedeutet das, was ich tue, ist nicht portabel?). Hier bedeutet mild Bash 2 bis Bash 4.
  • @jww [[ … ]] wurde hinzugefügt in bash 2.02. ((…)) wurde in bash 2.0 hinzugefügt.
  • @Giles – danke. Bash 2 ist für die meisten wahrscheinlich lächerlich. Es liegt an unserer Regierungsführung und an unserer Unwilligkeit Bash 2 und GCC 3 werden bei unseren Fedora 1-Tests angezeigt. Wir werden gelegentlich eine ältere Plattform freigeben, aber es muss Gründe dafür geben. Wir geben ' Abonnieren Sie nicht die Richtlinien für Abbruchware von Apple, Microsoft, Mozilla usw.
  • @jww Bitte haben Sie Verständnis dafür, dass || und wechselt von [ zu [[ und ((. Gleiche Priorität in [ (verwenden Sie Klammern, um die Reihenfolge der Auswertung zu steuern), aber & & hat in [[ und (( eine höhere Priorität als || (wie in C).
  • @Roland Nein, Klammern in [[ … ]] oder $((…)) dienen nur zur Gruppierung.

Antwort

Verwenden Sie [[:

if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ... 

Wenn Sie [ bevorzugen, funktioniert Folgendes:

if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ... 

Kommentare

  • Danke, Stephen. In meinem Fall habe ich Ihr erstes Beispiel folgendermaßen verwendet … regex = ' ^ [0-9] + $ ' length = $ {#datearg} if! [[$ datearg = ~ $ regex & & $ length -eq 8]]; dann echo " Fehler: Keine Zehntel von 8 "; fi

Antwort

Verwenden Sie anstelle Ihres Operators den Operator -o verschachtelt ||. Sie können auch -a verwenden, um & & bei Bedarf in Ihren anderen Anweisungen zu ersetzen

 EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true if [ "$A" -eq "0" -o "$B" -ne "0" ] && [ "$C" -eq "0" ]; then echo success;fi 

Kommentare

  • Danke. Ich bin auf die -a und -o gestoßen, habe aber nicht mit ihnen experimentiert. Jemand von Stack Overflow sagte, er solle es vermeiden. Ich stimmte ihnen größtenteils zu, da das Skript mit ihnen weniger lesbar ist.
  • … aber portabler.
  • @Kusalananda – Vielen Dank für die Heads-Ups zur Portabilität. Das Skript muss auf Systemen mit Bash 2 bis Bash 4 ausgeführt werden. Wird [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]] Probleme damit haben?
  • Es wird keine Probleme geben, solange Sie bash oder eine andere Shell, die [[ ... ]] versteht.
  • Die Kehrseite der Verwendung von -a ist, dass es nicht ' t Kurzschluss, wenn der erste Ausdruck falsch ist. Wenn Sie sich also auf einen Kurzschluss verlassen, um zu verhindern, dass ein potenziell tödlicher zweiter Ausdruck ausgeführt wird, können Sie -a nicht verwenden. Beispiel: pastebin.com/zM77TXW1

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.