So verwenden Sie set und pipefail in Bash-Skripten unter Linux

Veröffentlicht: 2022-06-25
Linux-Terminal auf einem Laptop-Bildschirm vor blauem Hintergrund.
fatmawati achmad zaenuri/Shutterstock.com

Die Linux-Befehle set und pipefail , was passiert, wenn ein Fehler in einem Bash-Skript auftritt. Es gibt mehr zu bedenken, als dass es aufhören oder weitermachen sollte.

RELATED: The Beginner's Guide to Shell Scripting: The Basics

Bash-Skripte und Fehlerbedingungen

Bash-Shell-Skripte sind großartig. Sie sind schnell zu schreiben und müssen nicht kompiliert werden. Jede sich wiederholende oder mehrstufige Aktion, die Sie ausführen müssen, kann in ein praktisches Skript verpackt werden. Und da Skripte alle Standard-Linux-Dienstprogramme aufrufen können, sind Sie nicht auf die Fähigkeiten der Shell-Sprache selbst beschränkt.

Es können jedoch Probleme auftreten, wenn Sie ein externes Dienstprogramm oder Programm aufrufen. Wenn dies fehlschlägt, wird das externe Dienstprogramm geschlossen und einen Rückgabecode an die Shell senden, und es kann sogar eine Fehlermeldung an das Terminal ausgeben. Aber Ihr Skript wird weiter verarbeitet. Vielleicht wolltest du das nicht. Wenn ein Fehler früh in der Ausführung des Skripts auftritt, kann dies zu schlimmeren Problemen führen, wenn der Rest des Skripts ausgeführt werden darf.

Was ist die Bash-Shell und warum ist sie für Linux so wichtig?
RELATED Was ist die Bash-Shell und warum ist sie für Linux so wichtig?

Sie könnten den Rückgabecode jedes externen Prozesses nach Abschluss überprüfen, aber das wird schwierig, wenn Prozesse in andere Prozesse geleitet werden. Der Rückgabecode stammt vom Prozess am Ende der Pipe, nicht von dem in der Mitte, der fehlgeschlagen ist. Natürlich können auch innerhalb Ihres Skripts Fehler auftreten, z. B. wenn Sie versuchen, auf eine nicht initialisierte Variable zuzugreifen.

Mit den Befehlen set und pipefile können Sie entscheiden, was passiert, wenn solche Fehler auftreten. Sie ermöglichen es Ihnen auch, Fehler zu erkennen, selbst wenn sie mitten in einer Rohrleitungskette auftreten.

Hier erfahren Sie, wie Sie sie verwenden.

Demonstrieren des Problems

Hier ist ein triviales Bash-Skript. Es gibt zwei Textzeilen an das Terminal zurück. Sie können dieses Skript ausführen, wenn Sie den Text in einen Editor kopieren und als „script-1.sh“ speichern.

 #!/bin/bash

Echo Dies wird zuerst passieren 
Echo Dies wird als zweites passieren

Um es ausführbar zu machen, müssen Sie chmod verwenden:

 chmod +x script-1.sh

Sie müssen diesen Befehl für jedes Skript ausführen, wenn Sie es auf Ihrem Computer ausführen möchten. Lassen Sie uns das Skript ausführen:

 ./script-1.sh 

Ausführen eines einfachen Skripts ohne Fehler.

Die zwei Textzeilen werden wie erwartet an das Terminalfenster gesendet.

Lassen Sie uns das Skript leicht ändern. Wir bitten ls , die Details einer Datei aufzulisten, die nicht existiert. Dies wird fehlschlagen. Diese haben wir als „script-2.sh“ gespeichert und ausführbar gemacht.

 #!/bin/bash

Echo Dies wird zuerst passieren
ls imaginärer Dateiname
Echo Dies wird als zweites passieren

Wenn wir dieses Skript ausführen, sehen wir die Fehlermeldung von ls .

 ./script-2.sh 

Ausführen eines Skripts und Generieren einer Fehlerbedingung.

Obwohl der Befehl ls fehlschlug, wurde das Skript weiter ausgeführt. Und obwohl während der Ausführung des Skripts ein Fehler aufgetreten ist, ist der Rückgabecode vom Skript an die Shell Null, was auf Erfolg hinweist. Wir können dies mit echo und dem $? Variable, die den letzten Rückgabecode enthält, der an die Shell gesendet wurde.

 Echo $? 

Überprüfen des Rückkehrcodes für das zuletzt ausgeführte Skript.

Die gemeldete Null ist der Rückgabecode des zweiten Echos im Skript. Es gibt also zwei Probleme mit diesem Szenario. Das erste ist, dass das Skript einen Fehler hatte, aber weiter ausgeführt wurde. Das kann zu anderen Problemen führen, wenn der Rest des Skripts erwartet oder davon abhängt, dass die Aktion tatsächlich erfolgreich war. Und zweitens, wenn ein anderes Skript oder ein anderer Prozess den Erfolg oder Misserfolg dieses Skripts überprüfen muss, erhält es ein falsches Ergebnis.

Die Option set -e

Die Option set -e (exit) bewirkt, dass ein Skript beendet wird, wenn einer der von ihm aufgerufenen Prozesse einen Rückgabecode ungleich Null generiert. Alles, was nicht Null ist, wird als Fehler angesehen.

Indem wir die Option set -e am Anfang des Skripts hinzufügen, können wir sein Verhalten ändern. Dies ist „script-3.sh“.

 #!/bin/bash 
setze -e

Echo Dies wird zuerst passieren
ls imaginärer Dateiname
Echo Dies wird als zweites passieren

Wenn wir dieses Skript ausführen, sehen wir die Wirkung von set -e .

 ./script-3.sh
 Echo $? 

Beenden eines Skripts bei einer Fehlerbedingung und korrektes Setzen des Rückgabecodes.

Das Skript wird angehalten und der an die Shell gesendete Rückgabecode ist ein Wert ungleich Null.

Umgang mit Fehlern in Rohren

Rohrleitungen machen das Problem noch komplexer. Der Rückkehrcode, der aus einer über Pipe geleiteten Befehlsfolge kommt, ist der Rückkehrcode des letzten Befehls in der Kette. Wenn ein Befehl in der Mitte der Kette fehlschlägt, sind wir wieder bei Null. Dieser Rückkehrcode geht verloren und das Skript wird mit der Verarbeitung fortfahren.

Wir können die Auswirkungen von Piping-Befehlen mit unterschiedlichen Rückkehrcodes sehen, indem wir die eingebauten true und false -Shells verwenden. Diese beiden Befehle erzeugen lediglich einen Rückkehrcode von null bzw. eins.

 Stimmt
 Echo $?
 FALSCH
 Echo $? 

Die eingebauten True- und False-Befehle der Bash-Shell.

Wenn wir false an true übergeben – wobei false einen fehlgeschlagenen Prozess darstellt – erhalten wir den Rückgabecode von true von null.

 falsch | Stimmt
 Echo $? 

False in True umwandeln.

Bash hat eine Array-Variable namens PIPESTATUS , die alle Rückgabecodes von jedem Programm in der Pipe-Kette erfasst.

 falsch | wahr | falsch | Stimmt
 echo "${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]} ${PIPESTATUS[3]}" 

Verwenden von PIPESTATUS, um den Rückkehrcode aller Programme in einer Pipe-Kette anzuzeigen.

PIPESTATUS die Rückgabecodes nur, bis das nächste Programm ausgeführt wird, und der Versuch festzustellen, welcher Rückgabecode zu welchem ​​Programm gehört, kann sehr schnell sehr unübersichtlich werden.

Hier kommen set -o (Optionen) und pipefail ins Spiel. Dies ist „script-4.sh“. Dadurch wird versucht, den Inhalt einer Datei, die nicht existiert, in wc zu leiten.

 #!/bin/bash 
setze -e

Echo Dies wird zuerst passieren
cat script-99.sh | WC-l
Echo Dies wird als zweites passieren

Dies schlägt fehl, wie wir erwarten würden.

 ./script-4.sh
 Echo $? 

Ausführen eines Skripts mit einem Fehler in einer Pipe-Kette.

Die erste Null ist die Ausgabe von wc , die uns mitteilt, dass keine Zeilen für die fehlende Datei gelesen wurden. Die zweite Null ist der Rückgabecode des zweiten echo .

Wir fügen das -o pipefail , speichern es als „script-5.sh“ und machen es ausführbar.

 #!/bin/bash 
set -eo pipefail

Echo Dies wird zuerst passieren
cat script-99.sh | WC-l
Echo Dies wird als zweites passieren

Lassen Sie uns das ausführen und den Rückgabecode überprüfen.

 ./script-5.sh
 Echo $? 

Ausführen eines Skripts, das Fehler in Pipe-Ketten abfängt und den Rückgabecode korrekt festlegt.

Das Skript wird angehalten und der zweite echo Befehl wird nicht ausgeführt. Der an die Shell gesendete Rückgabecode ist eins und zeigt korrekt einen Fehler an.

VERWANDT: So verwenden Sie den Echo-Befehl unter Linux

Nicht initialisierte Variablen abfangen

Nicht initialisierte Variablen können in einem realen Skript schwer zu erkennen sein. Wenn wir versuchen, den Wert einer nicht initialisierten Variablen zu echo echo eine leere Zeile aus. Es löst keine Fehlermeldung aus. Der Rest des Skripts wird weiterhin ausgeführt.

Dies ist script-6.sh.

 #!/bin/bash 
set -eo pipefail

echo "$notset" 
echo "Ein weiterer Echobefehl"

Wir lassen es laufen und beobachten sein Verhalten.

 ./script-6.sh
 Echo $? 

Ausführen eines Skripts, das keine nicht initialisierten Variablen erfasst.

Das Skript springt über die nicht initialisierte Variable und fährt mit der Ausführung fort. Der Rückkehrcode ist Null. Der Versuch, einen solchen Fehler in einem sehr langen und komplizierten Skript zu finden, kann sehr schwierig sein.

So arbeiten Sie mit Variablen in Bash
RELATED So arbeiten Sie mit Variablen in Bash

Wir können diese Art von Fehler mit der Option set -u (unset) abfangen. Wir fügen das zu unserer wachsenden Sammlung von Set-Optionen oben im Skript hinzu, speichern es als „script-7.sh“ und machen es ausführbar.

 #!/bin/bash 

set -eou pipefail

echo "$notset" 

echo "Ein weiterer Echobefehl"

Lassen Sie uns das Skript ausführen:

 ./script-7.sh
 Echo $? 

Ausführen eines Skripts, das nicht initialisierte Variablen erfasst.

Die nicht initialisierte Variable wird erkannt, das Skript wird angehalten und der Rückgabecode wird auf eins gesetzt.

Die Option -u (unset) ist intelligent genug , um nicht durch Situationen ausgelöst zu werden, in denen Sie legitim mit einer nicht initialisierten Variablen interagieren können.

In „script-8.sh“ prüft das Skript, ob die Variable New_Var initialisiert ist oder nicht. Sie möchten nicht, dass das Skript hier aufhört, in einem realen Skript führen Sie die weitere Verarbeitung durch und kümmern sich selbst um die Situation.

Beachten Sie, dass wir die Option -u als zweite Option in der set-Anweisung hinzugefügt haben. Die Option -o pipefail muss an letzter Stelle stehen.

 #!/bin/bash 

set -euo pipefail

if [ -z "${Neue_Var:-}" ]; dann 

echo "New_Var ist kein Wert zugewiesen." 

fi

In „script-9.sh“ wird die nicht initialisierte Variable getestet und wenn sie nicht initialisiert ist, wird stattdessen ein Standardwert bereitgestellt.

 #!/bin/bash
set -euo pipefail

default_value=484
Wert=${Neue_Var:-$Standardwert}
echo "Neue_Var=$Wert"

Die Skripte dürfen bis zu ihrer Fertigstellung durchlaufen werden.

 ./script-8.sh
 ./script-9.sh 

Ausführen von zwei Skripts, bei denen die nicht initialisierten Variablen intern behandelt werden und die Option -u nicht ausgelöst wird.

Mit Axt versiegelt

Eine weitere praktische Option ist die Option set -x (Ausführen und Drucken). Wenn Sie Drehbücher schreiben, kann dies ein Lebensretter sein. Es gibt die Befehle und ihre Parameter aus, während sie ausgeführt werden.

Es gibt Ihnen eine schnelle „rohe und fertige“ Form der Ausführungsverfolgung. Das Isolieren von Logikfehlern und das Erkennen von Fehlern wird viel, viel einfacher.

Wir fügen die Option set -x zu „script-8.sh“ hinzu, speichern sie als „script-10.sh“ und machen sie ausführbar.

 #!/bin/bash
set -euxo pipefail

if [ -z "${Neue_Var:-}" ]; dann
  echo "New_Var ist kein Wert zugewiesen."
fi

Führen Sie es aus, um die Ablaufverfolgungslinien anzuzeigen.

 ./script-10.sh 

Ausführen eines Skripts mit -x Trace-Zeilen, die in das Terminal geschrieben werden.

Das Erkennen von Fehlern in diesen trivialen Beispielskripten ist einfach. Wenn Sie anfangen, kompliziertere Skripte zu schreiben, werden sich diese Optionen bewähren.