Wie man Fallen und Fehlerbehandlungsoptionen in Bash verwendet

Indeks
  1. Eine Funktion bei Exit ausführen
  2. Funktionen, Subshells und Prozesssubstitutionen Traps auslösen lassen
  3. Um "ERR"-Fallen in diesen Konstrukten zu nutzen, verwenden Sie die Option "set -E":
  4. Ein potenzieller Stolperstein bei der Verwendung von Fallen ist das Management der Komplexität von Subshells. Schauen Sie sich dieses Beispiel an:

Dieser Leitfaden hilft Ihnen, die Fehlerbehandlung in Bash-Skripten mit den Optionen `set -e` und `trap` zu optimieren, um robustere und lesbarere Skripte zu erstellen.

Lernen Sie Bash oder möchten Sie die Fehlerbehandlung in Ihren Skripten verbessern? Die Regeln zur Fehlerbehandlung können etwas knifflig sein, daher habe ich diesen kompakten Leitfaden zusammengestellt, um ihre Geheimnisse zu entwirren.

Das anfängliche Muster, das ich gelernt habe – und oft das erste Empfohlene – ist die Option set -e. Sie sorgt einfach dafür, dass Ihr Skript beendet wird, wenn ein nicht-null Exit-Code erkannt wird. Für diejenigen, die es nicht wissen: Ein Exit-Code ist eine Zahl, die von allen Programmen unter Linux zurückgegeben wird, und wenn er nicht null ist, handelt es sich um einen Fehler. Den Exit-Code des zuletzt ausgeführten Prozesses können Sie mit echo $? sehen.

Schauen wir uns ein paar Beispiele an.

Wenn alles in Ordnung ist:

#!/usr/bin/env bash ls / echo Exit code: $?

Hier ist ein Versuch, ein nicht existierendes Verzeichnis aufzulisten (ein Fehler):

#!/usr/bin/env bash ls /foo echo Exit code: $?

Sehen Sie, wie es einen nicht-null Exit-Code zurückgibt?

Nun nutzen wir set -e:

#!/usr/bin/env bash set -e ls /foo echo "Exits before this point."

Wir sehen, dass das Skript die Echo-Anweisung nie erreicht und nur die Fehlermeldung von "ls" anzeigt.

Die Option "set -e" ist nützlich, um die Ausführung zu stoppen, wenn ein Schritt fehlschlägt (ähnlich wie eine Postconditionsbehauptung), zum Beispiel beim Verschieben einer Datei, die nicht korrekt heruntergeladen wurde, oder beim Ändern von Dateiberechtigungen in einem Verzeichnis, das nicht existiert.

Es führt auch oft zu saubereren Skripten, da Sie keine Bedingungen schreiben müssen, um den Programmstatus zu überprüfen:

 if curl ...; then if mv ...; then if ! chmod ...; then echo "Konnte die Dateiberechtigungen nicht ändern." exit 1 fi else echo "Konnte die Datei nicht verschieben." exit 2 fi else echo "Konnte foo nicht herunterladen." exit 3 fi

Stattdessen können Sie schreiben:

 set -e curl ... mv ... chmod ...

Das ist ähnlich zum Never Nester Muster, bei dem das Ziel darin besteht, bedingte Verzweigungen abzuflachen. Oder, Sie könnten es als eine implizite Form von Behauptungen sehen, die einen akzeptablen Programmstatus durchsetzt, bevor die Ausführung fortgesetzt wird. So oder so, es ist weniger Code, was besser lesbar ist, und das ist immer ein großer Gewinn.

Eine Funktion bei Exit ausführen

Beim Beenden bei Fehlern ist es eine Sache, aber was ist mit der Aufräumung, nachdem Sie fertig sind? Zum Beispiel haben Sie ein Archiv heruntergeladen, es entpackt und versucht, eine einzelne Datei daraus zu verschieben, aber das Skript beendet sich dann wegen eines Fehlers. Nach Abschluss der Ausführung bleiben diese ungenutzten Dateien in Ihrem Dateisystem und vermüllen es.

Um unser Skript sauber zu halten, wollen wir unübersichtliche Fehlerbehandlungsverzweigungen vermeiden, und hier kommen Traps ins Spiel. Ein Trap führt eine Funktion (oder einen Befehl) aus, wenn ein Ereignis eintritt (ein sogenannter Signal):

 set -e cd /tmp function cleanup() { rm -rf foo.zip rm -rf foo/ } trap cleanup ERR curl ... --output foo.zip unzip foo.zip mv foo/bar.csv /root/ 

Signale umfassen ERR, EXIT, INT (Tastaturunterbrechung) und andere. Verwenden Sie das Signal "ERR", um nur Fehler abzufangen, oder "EXIT", um auszuführen, wann immer das Skript stoppt (auch bei einem Fehler).

Diese Signale sind die gebräuchlichsten, aber Sie können eine vollständige Liste mit trap -l in Bash anzeigen. Beachten Sie, dass andere Shells möglicherweise unterschiedliche Namenskonventionen verwenden – einschließlich oder ausschließend eines "SIG"-Präfixes (z. B. SIGINT). Bash ist flexibel, da Sie beide verwenden können.

Wenn Sie einen Befehl (mit Leerzeichen) ausführen, wickeln Sie ihn in Anführungszeichen: trap "rm -rf foo.zip" ERR. Sie können auch mehrere Signale angeben: trap foo ERR INT.

Funktionen, Subshells und Prozesssubstitutionen Traps auslösen lassen

Wenn Sie die Option "set -e" verwenden, lösen Funktionen, Subshells und Befehlsersetzungen keine ERR-Traps aus:

#!/usr/bin/env bash set -e trap "echo Trap executed." ERR foo() { ls /bar } foo echo "Exits before this.

Um "ERR"-Fallen in diesen Konstrukten zu nutzen, verwenden Sie die Option "set -E":

#!/usr/bin/env bash set -E trap "echo Falle ausgeführt." ERR foo() { ls /bar } foo echo "Das Skript beendet sich nicht, also werden wir diese Nachricht sehen."

Beachten Sie, dass die Falle zweimal ausgeführt wird? Das liegt daran, dass das Skript bei einem Fehler nicht beendet wird (set -e). Wenn die Funktion einen Fehlercode ungleich Null zurückgibt ("ls /bar"), tritt technisch ein Fehler auf, und somit wird auch die Falle ausgeführt. Wir können das beheben, indem wir set -eE verwenden:

#!/usr/bin/env bash set -eE trap "echo Falle ausgeführt." ERR foo() { ls /bar } foo echo "Beendet sich vor diesem Punkt."

Ein potenzieller Stolperstein bei der Verwendung von Fallen ist das Management der Komplexität von Subshells. Schauen Sie sich dieses Beispiel an:

set -e trap "echo Falle ausgeführt." ERR (ls /foo)

Es wird die Falle ausgeführt, was nicht passieren sollte, da wir set -E nicht verwendet haben. Was passiert hier? Ich konnte nichts Konkretes finden, aber was ich zusammentragen kann:

  1. Subshells sind Kindprozesse, die Forks (Klonen) des aufrufenden Prozesses (einschließlich der Option "set -e"), sodass die Subshell ebenfalls bei einem Fehler beendet wird.
  2. Subshells (und andere) erben standardmäßig keine Fallen, daher wissen wir, dass sie nicht von der Subshell ausgeführt wird.
  3. "ls /foo" gibt einen Wert ungleich Null zurück und verursacht, dass die Subshell mit diesem Code beendet wird.

Angesichts aller drei Punkte scheint die Subshell mit einem Wert ungleich Null zu enden, und da der Elternprozess diesen Fehler erkennt, wird die Falle ausgelöst.

Weitere Beweise:

set -e trap "echo Falle ausgeführt." ERR ( set +e ls /foo exit 0 )

Die Regeln, die das Verhalten von Fallen regeln, sind komplex, daher habe ich eine Zusammenfassung basierend auf meinen Beobachtungen erstellt. Die Experimente verwendeten nur set -e (kein set -E):

Top-Level set -eFunktion trifft auf Fehlerset +e in FunktionFalle wird ausgelöst

Die ersten drei Spalten definieren den Kontext, und die vierte dokumentiert das Ergebnis.

Betrachten Sie die erste Zeile: set -e wird nicht verwendet, eine Funktion trifft auf einen Fehler, und es wurde set -e innerhalb des Funktionsscopes deaktiviert.

Die Daten deuten darauf hin, dass beim Aktivieren von set -e auf oberster Ebene die Funktion dessen Wert erbt und folglich sofort beendet wird, aber da sie keine Fallen erbt (set -E), wird eine Falle nicht aufgerufen.

Wenn Sie set -E verwenden, lösen Funktionen (und andere Konstrukte) ihre eigenen geerbten Fallen aus, und die Regeln werden einfacher.

In den meisten Fällen, wenn eine Falle gesetzt wird, verwenden Sie set -E, da dies die Regeln erheblich vereinfacht. Seien Sie sich jedoch bewusst, dass Subshells und Prozesssubstitutionen geforkte Prozesse sind, die ihre eigenen umwelttechnischen Eigenheiten mit sich bringen.

Darüber hinaus verwende ich immer die Option "set -e", da es normalerweise nicht wünschenswert ist, ein Skript nach dem Auftreten eines Fehlers fortzusetzen. Für Randfälle können Sie Fehler mit "|| true" unterdrücken:

set -e ls /foo || true echo 'Dies wird ausgegeben, weil "|| true" den Fehler unterdrückt.'

Kurz gesagt, die Verwendung von set -eE ist der direkteste Ansatz.

Bist du neugierig auf weitere Artikel wie Wie man Fallen und Fehlerbehandlungsoptionen in Bash verwendet? Entdecke spannende Inhalte in der Kategorie Linux.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Go up