Verwirrende Verwendung von && und || Betreiber

93

Ich habe eine /etc/rc.d/init.d/sendmailDatei durchgesehen (ich weiß, dass dies kaum verwendet wird, aber ich lerne für eine Prüfung) und bin ein bisschen verwirrt über die &&und die ||Operatoren. Ich habe gelesen, wo sie in Aussagen wie verwendet werden können:

if [ test1 ] && [ test2 ]; then
     echo "both tests are true"
elif [ test1 ] || [ test2 ]; then
     echo "one test is true"
fi

Dieses Skript zeigt jedoch einzeilige Anweisungen wie:

[ -z "$SMQUEUE" ] && SMQUEUE="QUEUE"
[ -f /usr/sbin/sendmail ] || exit 0

Diese scheinen die Operatoren &&und ||zu verwenden, um auf der Grundlage von Tests Antworten auszulösen, aber ich konnte keine Dokumentation zu dieser speziellen Verwendung dieser Operatoren finden. Kann jemand erklären, was diese in diesem speziellen Kontext tun?

Josh-Cain
quelle

Antworten:

141

Die rechte Seite von &&wird nur ausgewertet, wenn der Ausgangsstatus der linken Seite Null ist (dh wahr). ||ist das Gegenteil: es wird die rechte Seite nur ausgewertet, wenn der Ausgangsstatus der linken Seite ungleich Null ist (dh falsch).

Sie können [ ... ]ein Programm mit einem Rückgabewert betrachten. Wenn der Test in true ergibt, wird null zurückgegeben. Andernfalls wird ein Wert ungleich Null zurückgegeben.

Beispiele:

$ false && echo howdy!

$ true && echo howdy!
howdy!
$ true || echo howdy!

$ false || echo howdy!
howdy!

Zusätzliche Hinweise:

Wenn Sie dies tun which [, werden Sie vielleicht feststellen, dass dies [tatsächlich auf ein Programm verweist! Es ist jedoch normalerweise nicht derjenige, der in Skripten ausgeführt wird. laufe um type [zu sehen was tatsächlich läuft. Wenn Sie wan das Programm versuchen verwenden, geben nur den vollständigen Pfad wie folgt: /bin/[ 1 = 1.

Shawn J. Goff
quelle
6
Wenn Sie "X oder Y" sehen, testen Sie X. Wenn dies zutrifft, kennen Sie bereits die Antwort auf "X oder Y" (es ist wahr), sodass Sie Y nicht testen müssen. Wenn dies zutrifft, kennen Sie die Antwort nicht Antworte auf "X oder Y", also musst du Y testen. Wenn du "X und Y" siehst, testest du X. Wenn es falsch ist, kennst du bereits die Antwort auf "X und Y" (es ist falsch), also Sie müssen Y nicht testen. Wenn X wahr ist, müssen Sie Y testen, um festzustellen, ob "X und Y" wahr sind.
David Schwartz
2
Anstelle von "Wenn die linke Seite Null zurückgibt" würde ich schreiben "Wenn der Beendigungsstatus des Befehls auf der linken Seite Null ist". Ich finde "return" ein bisschen mehrdeutig, da die Ausgabe und der Exit-Status beide als "Rückgabewerte" betrachtet werden können
Glenn Jackman
Sie können nicht nur „ betrachten [ ... ] ein Programm zu sein“, in vielen Fällen ist es ist . Es ist häufig in der Datei /bin/[oder /usr/bin/[.
LS
5
C-Programmierer werden das sehr verwirrend finden. Dort bedeutet 0 falsch ... Während in Shellscripting 0 wahr ... Geist geblasen.
Calmarius
Eine andere, die Sie erwähnen könnten, ist testanstelle von ifoder [. Und if [und if testscheinen mit [und testohne ersichtlichen Reim oder Grund durchsetzt zu sein. testtaucht gelegentlich auf, wie auf config.site für Vendor Libs auf Fedora x86_64 .
59

Hier ist mein Spickzettel:

  • "A; B" Führen Sie A und dann B aus, unabhängig vom Erfolg von A
  • "A && B" Führen Sie B aus, wenn A erfolgreich war
  • "A || B" Führen Sie B aus, wenn A fehlgeschlagen ist
  • "A &" Führe A im Hintergrund aus.
user177073
quelle
Es gibt hier einige interessante Parallelen zur Lambda-Berechnung, die in funktionierendem JavaScript gezeigt werden (definieren Sie die Variablen in der richtigen Reihenfolge). "links (aka true)": (a => b => a). "Recht (aka false)": (a => b => b). "A; B" "dann" (a => b => (() => b())(a())). "A && B" "wenn ohne sonst (wann)" (a => b => a()(() => right)(b)). "A || B" "sonst ohne wenn (außer)" (a => b => a()(b)(() => right)). msgstr "a & b || c" "ifThenElse" (a => b => c => (unless(when(a)(b))(c))()).
Dmitry
1
beachte, dass in bash left analog 0 / empty string ist, right analog ist alles andere.
Dmitry
28

Die Antwort von @ Shawn-j-Goff von oben zu erweitern, &&ist ein logisches UND und ||ein logisches ODER.

Siehe diesen Teil des Advanced Bash Scripting Guide. Einige der Inhalte aus dem Link als Benutzerreferenz wie unten.

&& UND

if [ $condition1 ] && [ $condition2 ]
#  Same as:  if [ $condition1 -a $condition2 ]
#  Returns true if both condition1 and condition2 hold true...

if [[ $condition1 && $condition2 ]]    # Also works.
#  Note that && operator not permitted inside brackets
#+ of [ ... ] construct.

|| ODER

if [ $condition1 ] || [ $condition2 ]
# Same as:  if [ $condition1 -o $condition2 ]
# Returns true if either condition1 or condition2 holds true...

if [[ $condition1 || $condition2 ]]    # Also works.
#  Note that || operator not permitted inside brackets
#+ of a [ ... ] construct.
Tim Kennedy
quelle
11

Aus meiner Erfahrung benutze ich die && und || Reduzieren einer if-Anweisung auf eine einzelne Zeile.

Angenommen, wir suchen nach einer Datei mit dem Namen /root/Sample.txt, dann würde die herkömmliche Iteration in der Shell wie folgt lauten:

if [ -f /root/Sample.txt ]
then
    echo "file found"
else
    echo "file not found"
fi

Diese 6 Zeilen können auf eine einzelne Zeile reduziert werden:

[[ -f /root/Sample.txt ]] && echo "file found" || echo "file not found"

Wenn Sie ein paar Iterationen ausführen, um Variablen zu setzen oder Dateien usw. zu erstellen, ist das Leben einfacher und das Skript sieht mit der Funktion if in einer Zeile glatter aus. Der einzige Nachteil ist, dass es etwas schwieriger wird, mehrere Befehle mit einer einzelnen Iteration zu implementieren Sie können Funktionen nutzen.

syme89
quelle
Das ist cool. Erinnert mich an den Objektcode (a == b)? Val = 1: val = 2;
GeneCode
Wie kann ich diesen Befehl verwenden, wenn ich einen Prozess im Hintergrund mit "&" ausführen möchte? Ich erhalte einen Syntaxfehler für./someScript.sh & && echo 'ok' || echo 'ko'
Katie
4

Es gibt den Begriff "Abkürzung".

Wann (expr1 && expr2)wird ausgewertet - expr2wird nur ausgewertet, wenn die exp1Bewertung "wahr" ist. Dies liegt daran, dass beide expr1UND expr2wahr sein müssen, um wahr (expr1 && expr2)zu sein. Wenn expr1"false" ausgewertet wird, expr2wird NICHT ausgewertet (Abkürzung), da (expr1 && expr2)"flase" bereits vorhanden ist.

Versuchen Sie Folgendes - nehmen Sie an, dass die Datei F1existiert und F2nicht existiert:

( [ -s F1 ] && echo "File Exists" )  # will print "File Exists" - no short cut
( [ -s F2 ] && echo "File Exists" )  # will NOT print "File Exists" - short cut

Ähnliches gilt für ||(oder) - aber das Kurzschneiden wird umgekehrt.

Larry
quelle
5
Die Logik wird üblicherweise als "Kurzschluss" bezeichnet. Ich habe noch nie den Ausdruck "Abkürzung" gesehen. Ich erwähne dies, um bei der Suche nach Referenzen zu helfen.
LS
-1

Die Beispiele in der Antwort von Shawn J. Goff sind richtig, aber die Erklärung ist umgekehrt. Bitte prüfe:

Die rechte Seite von && wird nur ausgewertet, wenn der Ausgangsstatus der linken Seite NONZERO ist. || ist das Gegenteil: Die rechte Seite wird nur ausgewertet, wenn der Ausgangsstatus für die linke Seite NULL ist.

Try2Help
quelle
3
Sie wissen, dass Exit-Code für Shells mit Null den Wert true hat und somit Exit-Code ungleich Null auf der linken Seite des &&Ergebnisses im gesamten Ausdruck false zurückgibt ?
Gegenmodus
1
Jemand hat Ihre Änderungen nicht genehmigt, da dies nicht Ihre Antwort war. Wenn Sie der Meinung sind, dass eine Antwort falsch ist, sollten Sie sie ablehnen und möglicherweise einen Kommentar hinterlassen. Wenn Sie der Meinung sind, dass eine Änderung erforderlich ist, sollten Sie einen Kommentar hinterlassen. Das Bearbeiten dient zum Korrigieren von Grammatik-, Formatierungs- und Rechtschreibfehlern, die die Bedeutung der Antwort nicht ändern.
Techraf
1
@countermode Es tut mir leid, Sie haben recht, ich dachte in Linux null = falsch und ungleich null = wahr (wie in C und vielen anderen Sprachen / Umgebungen / Plattformen). Ich entschuldige mich für das Missverständnis.
Try2Help