Welches ist besser: mit; oder &&, um mehrere Befehle in einer Zeile auszuführen?

428

In Tutorials und Anleitungen sehe ich oft kombinierte Befehle. Zum Beispiel,

sudo apt-get update && sudo apt-get install pyrenamer

Es scheint vier mögliche Anschlüsse zu sein: &, &&, ||und ;. Obwohl der & Konnektor für mich klar ist (er sendet einen Prozess in den Hintergrund und lässt das Terminal verfügbar), ist nicht klar, worin der Unterschied zwischen &&und besteht ;. Und ich wusste es nicht, ||bis Kayas Kommentar.

Die folgenden Fragen befassen sich mit dem Unterschied zwischen den beiden Konnektoren, aber meistens in den Kommentaren:

Hier sind einige verwandte Fragen:

  1. Was ist der Unterschied zwischen ;und &&?
  2. Wann sollten Sie sie jeweils verwenden? Es wäre schön, einige Anwendungsfälle zu sehen: Wenn ich einen Befehl ausführen und dann meinen Computer herunterfahren möchte, welchen Anschluss soll ich wählen?
  3. Was sind ihre Vorteile und Gefahren ? Robie Basak erwähnt in einem Kommentar zu dieser Antwort, dass ein Befehl wie cd /somewhere_else; rm -Rf *zum Beispiel destruktive Konsequenzen haben kann, wenn das erste Element in der Befehlskette ausfällt.
  4. Woher kommen sie, falls relevant?
don.joey
quelle
7
Es gibt einen anderen Konnektor, auf den Sie möglicherweise nicht gestoßen sind: Er ||ist derselbe wie, &&außer dass er den zweiten Befehl nur ausführt, wenn der erste mit einem Status ungleich Null (nicht erfolgreich) beendet wurde.
Kaya
4
Beachten Sie auch, dass das Ausführen Ihres Skripts mit set -edas Skript bei einem Fehler anhält, als ob alle Befehle mit verbunden wären &&.
Choroba
3
Niemand antwortete auf Qn 4 ... Ich vermute das Verhalten von && und || wurde von der Programmiersprache C inspiriert. Im Fall von (x && y) muss der gesamte Ausdruck falsch sein, wenn x false ergibt, damit ein Compiler die Auswertung von y optimieren kann, falls dies teuer ist. Die modernen C- und C ++ - Standards erfordern diese Optimierung tatsächlich , sodass Programme davon ausgehen können, dass y nicht ausgewertet wird, wenn x falsch ist. Zum Beispiel stürzt (ptr && ptr-> Tage> 31) nicht ab, auch wenn ptr null ist. Auch in C enden die Anweisungen mit; unabhängig davon, ob in derselben Zeile eine andere Anweisung steht oder nicht.
Kevin

Antworten:

773

Spickzettel:

A; B    # Run A and then B, regardless of success of A
A && B  # Run B if and only if A succeeded
A || B  # Run B if and only if A failed
A &     # Run A in background.
Jack
quelle
19
Und natürlich A & B &: Führen Sie A im Hintergrund aus, führen Sie dann B im Hintergrund aus (unabhängig vom Erfolg) und geben Sie die Kontrolle an die Shell zurück. Dies funktioniert oft in etwa so, als würden beide Prozesse gleichzeitig ausgeführt.
Begrenzte Versöhnung
4
Ist es möglich zu sagen: Führe a im Hintergrund aus, gefolgt von b im Hintergrund, nur wenn a funktioniert hat? (Ich schätze &&&?)
user230910
15
@ user230910: das wäre (A && B) &.
links ungefähr
5
Können Sie sich dazu auf ein maßgebliches Dokument beziehen?
Jaime Hablutzel
@Jack Wenn es von Cronjob ausgeführt wird, folgt es nicht ganz dieser Regel. Irgendeine Idee warum? Für eine Python-Datei
CodeGuru
77

&&Führt den zweiten Befehl nur aus, wenn der erste mit dem Status 0 beendet wurde (erfolgreich war). ;Führt beide Befehle aus, auch wenn der erste mit einem Status ungleich Null beendet wird.

Ihr Beispiel mit &&kann äquivalent umschrieben werden als

if sudo apt-get update ; then
    sudo apt-get install pyrenamer
fi
Choroba
quelle
Vielen Dank. Ich habe die Frage aktualisiert, um sicherzustellen, dass die verschiedenen Unterfragen leicht zu unterscheiden sind.
don.joey
5
@Private: Verwenden Sie diese Option, ;wenn der zweite Befehl den vorherigen nicht benötigt, um erfolgreich zu sein.
Choroba
31

Mit ;werden die Befehle ausgeführt, unabhängig davon, ob der erste Befehl erfolgreich ist oder nicht.

Verwenden des &&Befehls "Execute 2nd" nur, wenn der erste Befehl erfolgreich ausgeführt wurde (Status 0).

Beide werden aus unterschiedlichen Perspektiven eingesetzt. Wie für einen längeren Prozess, sagen wir für eine Installation, die Sie kompilieren und installieren müssen. du solltest make && make install. Die Installation wird also nur dann ausgeführt, wenn sie makeerfolgreich war.

Für abhängige Befehle sollten Sie also verwenden &&

Wring bash oder Befehle mit unabhängigen Befehlen verwenden ;

Wenn Sie also den Computer herunterfahren möchten, obwohl der erste Job fehlgeschlagen ist, verwenden Sie ihn ;. Wenn der erste Job jedoch vollständig erfolgreich sein soll, starten Sie den Herunterfahrvorgang&&

Wir sind
quelle
14

a ; bwird unabhängig vom Exit-Status von a ausgeführt. a && bwird nur dann ausgeführt, wenn a erfolgreich war.

Dies ist notwendig und ausreichend, um die ersten 3 Fragen zu beantworten. Insbesondere ist die 2 zu weit gefasst und kann nicht als "eine" definitive Antwort angegeben werden. Am besten entscheiden Sie im Einzelfall.

Was die vierte Frage betrifft : Sie sind Bash-Syntax .

Auch bei der Verwendung besteht keine Gefahr. Auch hier ist die obige Definition ausreichend. Es bedeutet, dass Sie schreiben, &&wenn bunbeabsichtigte Auswirkungen hat, wenn adies nicht gelingt. Es gibt keine Notwendigkeit für weitere Regeln oder Erklärungen, IMHO.

ignis
quelle
1

EIN; B # Führen Sie A und dann B aus, unabhängig vom Erfolg von A

A && B # Führen Sie B genau dann aus, wenn A erfolgreich war

A || B # Führen Sie B genau dann aus, wenn A fehlgeschlagen ist

A & # Führe A im Hintergrund aus.

Eine sehr gute Faustregel. Ich würde hinzufügen, dass in einigen Fällen die Verwendung dieser Befehle in einer Subshell sinnvoll ist, wenn wir sie als einzelne Einheit betrachten oder einige Operationsergebnisse nicht mit der aktuellen Shell koppeln möchten.

Beispiele:

- Verketten Sie die Ausgabe von zwei Befehlen:

(ls foo; ls bar) > single-result.txt

-in ein Verzeichnis gehen und dort einen Befehl ausführen, ohne das aktuelle Verzeichnis der Shell zu ändern:

(cd target-directory && jar -xf ../my-jar)
davidxxx
quelle