Die Operatoren &&
und ||
sind keine exakten Inline-Ersetzungen für if-then-else. Bei vorsichtiger Verwendung können sie jedoch fast dasselbe erreichen.
Ein einziger Test ist unkompliziert und eindeutig ...
[[ A == A ]] && echo TRUE # TRUE
[[ A == B ]] && echo TRUE #
[[ A == A ]] || echo FALSE #
[[ A == B ]] || echo FALSE # FALSE
Der Versuch, mehrere Tests hinzuzufügen, kann jedoch zu unerwarteten Ergebnissen führen ...
[[ A == A ]] && echo TRUE || echo FALSE # TRUE (as expected)
[[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
[[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
[[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)
Warum werden sowohl FALSE als auch TRUE wiederholt?
Was hier passiert, ist, dass wir das nicht erkannt haben &&
und ||
überladene Operatoren sind, die in bedingten Testklammern anders agieren [[ ]]
als in der UND- und ODER-Liste (bedingte Ausführung), die wir hier haben.
Aus der Bash-Manpage (bearbeitet) ...
Listen
Eine Liste ist eine Folge von einer oder mehreren Pipelines, die durch einen der Operatoren;, &, && oder ││ getrennt und optional durch eines von;, &, oder abgeschlossen sind. Von diesen Listenoperatoren haben && und ││ die gleiche Priorität, gefolgt von; und &, die den gleichen Vorrang haben.
Eine Folge von einer oder mehreren Zeilenumbrüchen kann in einer Liste anstelle eines Semikolons zur Begrenzung von Befehlen angezeigt werden.
Wenn ein Befehl vom Steueroperator & beendet wird, führt die Shell den Befehl im Hintergrund in einer Subshell aus. Die Shell wartet nicht auf den Abschluss des Befehls und der Rückgabestatus ist 0. Befehle durch ein; getrennt. werden nacheinander ausgeführt; Die Shell wartet darauf, dass die einzelnen Befehle der Reihe nach beendet werden. Der Rückgabestatus ist der Beendigungsstatus des zuletzt ausgeführten Befehls.
AND- und OR-Listen sind Sequenzen einer oder mehrerer Pipelines, die durch die Steueroperatoren && bzw. ││ getrennt sind. AND- und OR-Listen werden mit linker Assoziativität ausgeführt.
Eine UND-Liste hat die Form ...
command1 && command2
Befehl2 wird nur dann ausgeführt, wenn Befehl1 den Beendigungsstatus Null zurückgibt.
Eine ODER-Liste hat die Form ...
command1 ││ command2
Befehl2 wird genau dann ausgeführt, wenn Befehl1 einen Exit-Status ungleich Null zurückgibt.
Der Rückgabestatus von AND- und OR-Listen ist der Exit-Status des zuletzt ausgeführten Befehls in der Liste.
Zurück zu unserem letzten Beispiel ...
[[ A == B ]] || echo FALSE && echo TRUE
[[ A == B ]] is false
|| Does NOT mean OR! It means...
'execute next command if last command return code(rc) was false'
echo FALSE The 'echo' command rc is always true
(i.e. it successfully echoed the word "FALSE")
&& Execute next command if last command rc was true
echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"
Okay. Wenn das richtig ist, warum gibt das vorletzte Beispiel dann überhaupt etwas wieder?
[[ A == A ]] || echo FALSE && echo TRUE
[[ A == A ]] is true
|| execute next command if last command rc was false.
echo FALSE Since last rc was true, shouldn't it have stopped before this?
Nope. Instead, it skips the 'echo FALSE', does not even try to
execute it, and continues looking for a `&&` clause.
&& ... which it finds here
echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"
Das Risiko von Logikfehlern bei der Verwendung mehrerer Befehle &&
oder ||
in einer Befehlsliste ist sehr hoch.
Empfehlungen
Eine einzelne &&
oder ||
in einer Befehlsliste funktioniert wie erwartet, ist also ziemlich sicher. In Situationen, in denen Sie keine else-Klausel benötigen, kann Folgendes klarer sein (die geschweiften Klammern sind erforderlich, um die letzten zwei Befehle zu gruppieren) ...
[[ $1 == --help ]] && { echo "$HELP"; exit; }
Multiple &&
und ||
Operatoren, bei denen jeder Befehl mit Ausnahme des letzten ein Test ist (dh in eckigen Klammern [[ ]]
), sind normalerweise ebenfalls sicher, da sich alle Operatoren außer dem letzten wie erwartet verhalten. Der letzte Operator verhält sich eher wie eine then
or- else
Klausel.
&&
und die||
Shell-Operatorencmd1 && cmd2 || cmd3
dieselbe Priorität haben, hat das&&
In((...))
und[[...]]
Vorrang vor||
(((a || b && c))
is((a || (b && c)))
). Gleiches gilt für-a
/-o
intest
/[
undfind
und&
/|
inexpr
.