Warum ist Muster “Befehl || wahr ”nützlich?

79

Ich untersuche gerade Debian-Pakete und habe einige Codebeispiele gelesen. Und in jeder Zeile zum Beispiel ist das postinstSkript ein Muster.

some command || true
another command || true

Wenn also ein Befehl fehlschlägt, gibt die Zeile true zurück, aber ich sehe nicht, wie sich dies auf die Ausgabe des Programms auswirkt.

Zimmermann
quelle
5
FYI ||:ist eine andere idiomatische Art, dies zu schreiben ( :ein weiterer Eintrag in der eingebauten Tabelle, der auf Bourne verweist true- aber garantiert auch auf Bourne; für POSIX sh trueist dies ebenfalls garantiert - also auf Bourne mehr Knappheit als Effizienz in selbst entfernt-modernen Zeiten).
Charles Duffy

Antworten:

151

Der Grund für dieses Muster ist, dass Betreuerskripte in Debian-Paketen in der Regel mit beginnen set -e, was dazu führt, dass die Shell beendet wird, sobald ein Befehl (genau genommen Pipeline-, Listen- oder Verbundbefehl) mit einem Nicht-Null-Status beendet wird. Dies stellt sicher, dass sich keine Fehler ansammeln: Sobald etwas schief geht, wird das Skript abgebrochen.

In Fällen, in denen ein Befehl im Skript fehlschlagen darf, wird durch das Hinzufügen || truesichergestellt, dass der resultierende zusammengesetzte Befehl immer mit dem Status Null beendet wird, sodass das Skript nicht abgebrochen wird. Das Entfernen eines Verzeichnisses sollte beispielsweise kein schwerwiegender Fehler sein (das Entfernen eines Pakets wird verhindert). also würden wir verwenden

rmdir ... || true

since rmdirhat keine Option, um anzugeben, dass Fehler ignoriert werden sollen.

Stephen Kitt
quelle
4
Nun, ohne dass set -ees überhaupt einer Notwendigkeit bedarf || true, hielt ich es für wichtig, den Kontext bereitzustellen. Wenn Sie auf POWER merkwürdige Dinge bemerken, empfehle ich Ihnen dringend, Bugs ( reportbug) einzureichen !
Stephen Kitt
16
@MichaelFelt ist eigentlich set -enicht nur eine "Debian-Konvention", sondern ein gutes Programmiermuster, das man immer verwenden sollte. Sehen. zB davidpashley.com/articles/writing-robust-shell-scripts
Kay
2
pro die frage hier - warum || trueset -e verwendet wird ist der wahrscheinliche kontext und wahrscheinlich der häufigste. Ich verneige mich vor dieser Antwort! Buchstäblich ist es jedoch immer dann nützlich, wenn der Beendigungsstatus als irrelevant eingestuft wird UND (wie Sie durch den Artikellink hinzufügen) ich den Beendigungsstatus nicht als Teil meiner Skriptsteuerung verwende. Ich sehe utility (in set -e), würde aber nicht so weit gehen wie im Artikel und sagen "Jedes Skript, das Sie schreiben, sollte set -e oben einschließen". Es ist ein Programmierstil. "ALWAYS | Every" enthält einen eigenen Satz von Fallen - auch bekannt als - Absolutes Re: Wild-Card-Lösungen werden ALWAYSirgendwann nach hinten losgehen, auch bekannt als - keine kostenlosen Fahrten.
Michael Felt
1
@ Kay Das ist eine derzeit beliebte Perspektive, steckt aber letztendlich voller zahlreicher Annahmen, die die Portabilität des Skripts einschränken. Es gibt historische Inkonsistenzen mit dem set -eVerhalten. Es mag Ihnen egal sein, ob Ihre einzigen Ziele bashund die anderen relativ neuen Shells sind, auf denen Sie leben /bin/sh, aber die Situation ist differenzierter, wenn Sie alte Shells / Systeme unterstützen möchten.
mtraceur
2
@StephenKitt Sicheres Ding. Es gibt eine sehr gründliche Seite, die das set -eVerhalten verschiedener Muscheln von Sven Mascheck dokumentiert , obwohl diese Seite auch viele historische / alte Muscheln dokumentiert, die heute irrelevant sind. Es gibt auch diese beiden Seiten mit einem schmaleren modernen Fokus (Suche nach "set -e"): "lintsh" -Seite , autoconfs Portable Shell-Dokumentation -> Seite zur Einschränkung von Builtins
mtraceur
32

Es hat zwar keine Auswirkung auf die Ausgabe des gerade ausgeführten Programms - es ermöglicht dem Aufrufer, fortzufahren, als ob alles in Ordnung wäre, was auch die zukünftige Logik betrifft.

Umformuliert: es Masken des Fehlerstatus des vorherigen Befehls.

michael@x071:[/usr/sbin]cat /tmp/false.sh
#!/bin/sh
false

michael@x071:[/usr/sbin]cat /tmp/true.sh 
#!/bin/sh
false || true

michael@x071:[/usr/sbin]sh /tmp/false.sh; echo $?
1
michael@x071:[/usr/sbin]sh /tmp/true.sh; echo $? 
0
Michael Felt
quelle
6
Das ist wahr, aber es antwortet nicht, warum es nützlich ist, den Beendigungsstatus eines Befehls zu maskieren.
Moopet
4
set -e bedeutet, dass das Skript bei einer Rückkehr ungleich Null sofort beendet wird. Vielleicht möchten Sie an diesem bestimmten Ort nicht, dass dies geschieht!
Rackandboneman
Ich bin eine einfache Person - und für mich ist der einzige Grund, den Fehlerstatus zu maskieren, der, dass er "im Weg ist". set -e macht jeden fehler "im weg" wenn es dir vorher egal war. Ich mag die Diskussion, weil ich sie als eine gute Möglichkeit sehe, meine Skripte zu debuggen und zusätzliche Logik zu schreiben, um auf einen Fehler zu reagieren (z. B. || print - "xxx existierte hier ungleich Null". Wahrscheinlicher ist jedoch, dass ich eine habe Shell-Funktion 'fatal' und ich habe "etwas || fatales" unglückliches ". Wenn ein Skript einen fehlerhaften Status meldet oder sich nicht darum kümmert. -e plus || true maskiert Fehler. Wenn es das ist, was ich will - fein, Wenn nicht, fehlen mir Fehler
Michael Felt
was ich mich fragen muss ist: ist || true - eine Krücke zum Codieren (fauler Weg, um einen Fehler zu umgehen / hinter sich zu lassen, mit dem ich mich jetzt nicht befassen möchte), ein Debug-Tool (-e, aber nein || true) oder einfach ein Dogma darüber, was gute Codierungspraxis ist. Mit anderen Worten - Ich sehe es als ein Merkmal - mit potenziellem Nutzen. Ich sehe es nicht als einen Zauberstab, um alle zu heilen. Kurz gesagt - so wie Schönheit im Auge des Betrachters liegt - set -eund der || trueNutzen wird durch die Merkmale und Ziele von definiert der Programmierer
Michael Felt
6
@MichaelFelt Beachten Sie: git remote remove foo || true git remote add foo http://blah- Wir möchten den Fehler ignorieren, wenn die Fernbedienung nicht vorhanden ist.
user253751