Es gibt noch einige weitere Möglichkeiten, wie Sie dieses Problem angehen können. Angenommen, eine Ihrer Anforderungen besteht darin, ein Shell-Skript / eine Shell-Funktion mit einigen Shell-Befehlen auszuführen, zu überprüfen, ob das Skript erfolgreich ausgeführt wurde, und bei Fehlern Fehler auszulösen.
Die Shell-Befehle basieren im Allgemeinen auf zurückgegebenen Exit-Codes, um der Shell mitzuteilen, ob sie erfolgreich war oder aufgrund unerwarteter Ereignisse fehlgeschlagen ist.
Was Sie also tun möchten, fällt auf diese beiden Kategorien
- Beenden Sie bei einem Fehler
- Beenden und Bereinigen bei Fehler
Je nachdem, welche Sie ausführen möchten, stehen Shell-Optionen zur Verfügung. Für den ersten Fall stellt die Shell eine Option mit set -e
und für die zweite könnten Sie ein tun trap
aufEXIT
Soll ich exit
in meinem Skript / meiner Funktion verwenden?
Verwenden von exit
allgemeine Verbesserung verbessert die Lesbarkeit. In bestimmten Routinen möchten Sie, sobald Sie die Antwort kennen, sofort zur aufrufenden Routine zurückkehren. Wenn die Routine so definiert ist, dass nach dem Erkennen eines Fehlers keine weitere Bereinigung erforderlich ist, bedeutet das nicht sofortige Beenden, dass Sie mehr Code schreiben müssen.
In Fällen, in denen Sie Bereinigungsaktionen für das Skript ausführen müssen, um die Beendigung des Skripts zu bereinigen, wird die Verwendung nicht bevorzugt exit
.
Soll ich set -e
beim Beenden einen Fehler verwenden?
Nein!
set -e
war ein Versuch, der Shell "automatische Fehlererkennung" hinzuzufügen. Ihr Ziel war es, die Shell jedes Mal abzubrechen, wenn ein Fehler auftrat, aber es gibt viele potenzielle Fallstricke, zum Beispiel:
Die Befehle, die Teil eines if-Tests sind, sind immun. Wenn Sie im Beispiel erwarten, dass es bei der test
Überprüfung des nicht vorhandenen Verzeichnisses unterbrochen wird, wird dies nicht der Fall sein, und es wird die Bedingung else durchlaufen
set -e
f() { test -d nosuchdir && echo no dir; }
f
echo survived
Befehle in einer anderen als der letzten Pipeline sind immun. Im folgenden Beispiel wird der Exit-Code des zuletzt ausgeführten Befehls (ganz rechts) als ( cat
) betrachtet und war erfolgreich. Dies könnte durch Einstellen der set -o pipefail
Option vermieden werden, es ist jedoch immer noch eine Einschränkung.
set -e
somecommand that fails | cat -
echo survived
Empfohlen für den Gebrauch - trap
beim Verlassen
Das Urteil lautet: Wenn Sie in der Lage sein möchten, einen Fehler zu behandeln, anstatt blind zu beenden, anstatt zu verwenden set -e
, verwenden Sie ein trap
auf demERR
Pseudosignal.
Der ERR
Trap soll keinen Code ausführen, wenn die Shell selbst mit einem Fehlercode ungleich Null beendet wird, sondern wenn ein Befehl von dieser Shell ausgeführt wird, der nicht Teil einer Bedingung ist (wie in if cmd
, orcmd ||
), mit einem Exit-Status ungleich Null beendet wird .
Die allgemeine Praxis besteht darin, einen Trap-Handler zu definieren, der zusätzliche Debug-Informationen zu welcher Zeile und welcher Ursache für den Exit bereitstellt. Denken Sie daran, dass der Exit-Code des letzten Befehls, der das ERR
Signal verursacht hat , zu diesem Zeitpunkt noch verfügbar ist.
cleanup() {
exitcode=$?
printf 'error condition hit\n' 1>&2
printf 'exit code returned: %s\n' "$exitcode"
printf 'the command executing at the time of the error was: %s\n' "$BASH_COMMAND"
printf 'command present on line: %d' "${BASH_LINENO[0]}"
# Some more clean up code can be added here before exiting
exit $exitcode
}
und wir verwenden diesen Handler wie folgt über dem fehlerhaften Skript
trap cleanup ERR
Wenn Sie dies in einem einfachen Skript zusammenstellen, das false
in Zeile 15 die Informationen enthält, die Sie erhalten würden
error condition hit
exit code returned: 1
the command executing at the time of the error was: false
command present on line: 15
Das trap
bietet auch Optionen unabhängig vom Fehler, die Bereinigung nur nach Abschluss der Shell (z. B. wenn Ihr Shell-Skript beendet wird) auf Signal auszuführen EXIT
. Sie können auch mehrere Signale gleichzeitig abfangen. Die Liste der unterstützten Signale, auf die abgefangen werden soll, finden Sie auf der Handbuchseite trap.1p - Linux
Eine andere Sache, die Sie beachten sollten, wäre zu verstehen, dass keine der bereitgestellten Methoden funktioniert, wenn Sie sich mit Sub-Shells befassen. In diesem Fall müssen Sie möglicherweise Ihre eigene Fehlerbehandlung hinzufügen.
Auf einer Sub-Shell mit set -e
würde nicht funktionieren. Das false
ist auf die Sub-Shell beschränkt und wird niemals an die übergeordnete Shell weitergegeben. Um die Fehlerbehandlung hier durchzuführen, fügen Sie Ihre eigene Logik hinzu(false) || false
set -e
(false)
echo survived
Das gleiche passiert auch mit trap
. Die folgende Logik würde aus den oben genannten Gründen nicht funktionieren.
trap 'echo error' ERR
(false)