set -e
Beendet das Skript, wenn ein Exit-Code ungleich Null auftritt, außer unter bestimmten Bedingungen. Um die Gefahren seines Gebrauchs in wenigen Worten zusammenzufassen: Es verhält sich nicht so, wie die Leute denken, dass es es tut.
Meiner Meinung nach sollte es als gefährlicher Hack angesehen werden, der nur noch aus Kompatibilitätsgründen existiert. Die set -e
Anweisung wandelt die Shell nicht von einer Sprache, die Fehlercodes verwendet, in eine Sprache um, die einen ausnahmeartigen Steuerungsfluss verwendet. Sie versucht lediglich, dieses Verhalten nur schlecht zu emulieren.
Greg Wooledge hat viel zu den Gefahren von set -e
:
Im zweiten Link gibt es verschiedene Beispiele für das unintuitive und unvorhersehbare Verhalten von set -e
.
Einige Beispiele für das nicht intuitive Verhalten von set -e
(einige stammen aus dem obigen Wiki-Link):
set -e
x = 0
lass x ++
echo "x ist $ x"
Das Obige bewirkt, dass das Shell-Skript vorzeitig beendet wird, da let x++
0 zurückgegeben wird, was vom let
Schlüsselwort als falscher Wert behandelt und in einen Exit-Code ungleich Null umgewandelt wird. set -e
bemerkt dies und beendet das Skript unbemerkt.
set -e
[-d / opt / foo] && echo "Warnung: foo ist bereits installiert. Wird überschrieben." > & 2
echo "Installiere foo ..."
Das oben beschriebene Verfahren funktioniert wie erwartet und gibt eine Warnung aus, falls diese /opt/foo
bereits vorhanden ist.
set -e
check_previous_install () {
[-d / opt / foo] && echo "Warnung: foo ist bereits installiert. Wird überschrieben." > & 2
}
check_previous_install
echo "Installiere foo ..."
Das Obige endet, obwohl der einzige Unterschied darin besteht, dass eine einzelne Zeile in eine Funktion umgestaltet wurde, wenn /opt/foo
es nicht existiert. Dies liegt daran, dass die Tatsache, dass es ursprünglich funktionierte, eine besondere Ausnahme von seinem set -e
Verhalten darstellt. Wenn der a && b
Wert ungleich Null ist, wird er von ignoriert set -e
. Da es sich jedoch um eine Funktion handelt, entspricht der Exit-Code der Funktion dem Exit-Code dieses Befehls, und die Funktion, die einen Wert ungleich Null zurückgibt, beendet das Skript im Hintergrund.
set -e
IFS = $ '\ n' read -d '' -r -a config_vars <config
Das obige liest das Array config_vars
aus der Datei config
. Wie der Autor vielleicht beabsichtigt, wird es mit einem Fehler beendet, wenn config
es fehlt. Da der Autor möglicherweise nicht beabsichtigt, wird er stillschweigend beendet, wenn er config
nicht in einer neuen Zeile endet. Wenn set -e
hier nicht verwendet config_vars
würde , würden alle Zeilen der Datei enthalten sein, unabhängig davon, ob sie in einer neuen Zeile endete oder nicht.
Benutzer von Sublime Text (und anderen Texteditoren, die falsch mit Zeilenumbrüchen umgehen) sollten aufpassen.
set -e
should_audit_user () {
lokale Gruppe groups = "$ (groups" $ 1 ")"
für Gruppe in $ Gruppen; machen
if ["$ group" = audit]; dann gebe 0 zurück; fi
getan
return 1
}
if should_audit_user "$ user"; dann
Logger 'Blah'
fi
Der Autor kann davon ausgehen, dass $user
der groups
Befehl fehlschlägt , wenn der Benutzer aus irgendeinem Grund nicht vorhanden ist, und das Skript beendet wird, anstatt den Benutzer eine Aufgabe ungeprüft ausführen zu lassen. In diesem Fall wird die set -e
Kündigung jedoch niemals wirksam. Wenn $user
das Skript aus irgendeinem Grund nicht gefunden werden kann, gibt die should_audit_user
Funktion nur falsche Daten zurück, als wäre sie set -e
nicht in Kraft.
Dies gilt für alle Funktionen, die aus dem Bedingungsteil einer if
Anweisung aufgerufen werden , unabhängig davon, wie tief sie verschachtelt sind, unabhängig davon, wo sie definiert sind, auch wenn Sie set -e
sie erneut ausführen . Wenn Sie if
zu einem beliebigen Zeitpunkt verwenden, wird der Effekt vollständig deaktiviert, set -e
bis der Bedingungsblock vollständig ausgeführt ist. Wenn der Autor diese Fallstricke nicht kennt oder seinen gesamten Aufrufstapel in allen möglichen Situationen, in denen eine Funktion aufgerufen werden kann, nicht kennt, schreibt er fehlerhaften Code, und das falsche Sicherheitsgefühl, das von bereitgestellt wird, set -e
wird zumindest teilweise aufgehoben Schuld.
Selbst wenn der Autor sich dieser Fallstricke voll bewusst ist, besteht die Problemumgehung darin, Code auf die gleiche Weise zu schreiben, wie man es ohne ihn schreiben würde set -e
, wodurch dieser Switch weniger als nutzlos wird. Der Autor muss nicht nur den Code für die manuelle Fehlerbehandlung so schreiben, als ob er set -e
nicht in Kraft wäre, sondern das Vorhandensein von hat ihn set -e
möglicherweise in die Irre geführt, dass er dies nicht tun muss.
Einige weitere Nachteile von set -e
:
- Es fördert schlampigen Code. Fehlerbehandler werden völlig vergessen, in der Hoffnung, dass alles, was fehlgeschlagen ist, den Fehler auf eine vernünftige Weise meldet. Bei Beispielen wie
let x++
oben ist dies jedoch nicht der Fall. Wenn das Skript unerwartet abstürzt, geschieht dies normalerweise im Hintergrund, was das Debuggen behindert. Wenn das Skript nicht stirbt und Sie es erwartet haben (siehe vorherigen Aufzählungspunkt), haben Sie einen subtileren und heimtückischeren Fehler in Ihren Händen.
- Es führt die Menschen in ein falsches Sicherheitsgefühl. Sehen Sie noch einmal den
if
Aufzählungspunkt.
- Die Stellen, an denen die Shell endet, sind zwischen Shells oder Shell-Versionen nicht konsistent. Es ist möglich, versehentlich ein Skript zu schreiben, das sich in einer älteren Version von bash anders verhält,
set -e
weil zwischen diesen Versionen Optimierungen vorgenommen wurden.
set -e
ist ein umstrittenes Problem, und einige Leute, die sich der Probleme bewusst sind, empfehlen, dagegen vorzugehen, während andere nur empfehlen, vorsichtig zu sein, während es aktiv ist, um die Fallstricke zu kennen. Es gibt viele Anfänger in der Shell-Skripterstellung, die set -e
bei allen Skripten Abhilfe schaffen , aber im wirklichen Leben funktioniert das nicht so.
set -e
ist kein Ersatz für Bildung.