Ich möchte einen Fehler in einem Bash-Skript mit der Meldung "Testfälle fehlgeschlagen !!!" auslösen. Wie geht das in Bash?
Beispielsweise:
if [ condition ]; then
raise error "Test cases failed !!!"
fi
linux
bash
shell
error-handling
Naveen Kumar
quelle
quelle
echo you screwed up at ... | mail -s BUG $bugtrackeremailaddress
?Antworten:
Dies hängt davon ab, wo die Fehlermeldung gespeichert werden soll.
Sie können Folgendes tun:
Oder folgendes:
Wenn Sie eine Ausnahme auslösen, stoppen Sie die Programmausführung.
Sie können auch so etwas wie verwenden ,
exit xxx
woxxx
ist der Fehlercode Sie auf das Betriebssystem zurückkehren möchten (von 0 bis 255). Hier haben125
und64
sind nur zufällige Codes , die Sie mit verlassen können. Wenn Sie dem Betriebssystem mitteilen müssen, dass das Programm abnormal gestoppt wurde (z. B. ein Fehler aufgetreten ist), müssen Sie einen Exit-Code ungleich Null an übergebenexit
.Wie @chepner betonte, können Sie dies tun
exit 1
, was einen nicht spezifizierten Fehler bedeutet .quelle
1>&2
wird den Trick machenexit
selbst verwendet den Exit-Status des zuletzt abgeschlossenen Befehls, der 0 sein kann.exit 1
, was gemäß Konvention einen nicht spezifizierten Fehler bedeutet.Grundlegende Fehlerbehandlung
Wenn Ihr Testfallläufer für fehlgeschlagene Tests einen Code ungleich Null zurückgibt , können Sie einfach schreiben:
Oder noch kürzer:
Oder das kürzeste:
So beenden Sie mit dem Exit-Code von test_handler:
Erweiterte Fehlerbehandlung
Wenn Sie einen umfassenderen Ansatz verfolgen möchten, können Sie einen Fehlerbehandler haben:
Rufen Sie es dann auf, nachdem Sie Ihren Testfall ausgeführt haben:
oder
Die Vorteile eines Fehlerbehandlers mögen
exit_if_error
sind:if
Blöcken , die Exit-Codes auf Fehler testenFehlerbehandlungs- und Protokollierungsbibliothek
Hier ist eine vollständige Implementierung der Fehlerbehandlung und -protokollierung:
https://github.com/codeforester/base/blob/master/lib/stdlib.sh
Zusammenhängende Posts
__FILE__
,__LINE__
in Bashquelle
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
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 tuntrap
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?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 durchlaufenBefehle 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 derset -o pipefail
Option vermieden werden, es ist jedoch immer noch eine Einschränkung.Empfohlen für den Gebrauch -
trap
beim VerlassenDas 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 eintrap
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 ifcmd
, 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.und wir verwenden diesen Handler wie folgt über dem fehlerhaften Skript
Wenn Sie dies in einem einfachen Skript zusammenstellen, das
false
in Zeile 15 die Informationen enthält, die Sie erhalten würdenDas
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ührenEXIT
. 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 - LinuxEine 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. Dasfalse
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
Das gleiche passiert auch mit
trap
. Die folgende Logik würde aus den oben genannten Gründen nicht funktionieren.quelle
Hier ist eine einfache Falle, die das letzte Argument von STDERR ausgibt, die fehlgeschlagene Zeile meldet und das Skript mit der Zeilennummer als Exit-Code beendet. Beachten Sie, dass dies nicht immer großartige Ideen sind, aber dies zeigt einige kreative Anwendungen, auf denen Sie aufbauen können.
Ich habe das in ein Skript mit einer Schleife eingefügt, um es zu testen. Ich überprüfe nur, ob einige Zufallszahlen getroffen wurden. Sie könnten tatsächliche Tests verwenden. Wenn ich auf Kaution gehen muss, rufe ich false (was die Falle auslöst) mit der Nachricht an, die ich werfen möchte.
Lassen Sie den Trap für eine erweiterte Funktionalität eine Verarbeitungsfunktion aufrufen. Sie können immer eine case-Anweisung für Ihr Argument ($ _) verwenden, wenn Sie mehr Bereinigung usw. durchführen müssen. Weisen Sie einer var für ein wenig syntaktischen Zucker zu -
Beispielausgabe:
Offensichtlich könnten Sie
Viel Raum für Designverbesserungen.
Die Nachteile sind die Tatsache, dass
false
es nicht schön ist (also der Zucker), und andere Dinge, die die Falle auslösen, könnten ein wenig dumm aussehen. Trotzdem mag ich diese Methode.quelle
Sie haben zwei Möglichkeiten: Leiten Sie die Ausgabe des Skripts in eine Datei um, führen Sie eine Protokolldatei in das Skript ein und
Hier nehmen Sie an, dass das Skript alle notwendigen Informationen einschließlich Warn- und Fehlermeldungen ausgibt. Sie können die Ausgabe dann in eine Datei Ihrer Wahl umleiten.
Der obige Befehl leitet sowohl die Standardausgabe als auch die Fehlerausgabe in Ihre Protokolldatei um.
Mit diesem Ansatz müssen Sie keine Protokolldatei in das Skript einfügen, sodass die Logik ein wenig einfacher ist.
Fügen Sie in Ihrem Skript eine Protokolldatei hinzu, indem Sie sie entweder fest codieren:
oder Übergeben an einen Parameter:
Es ist eine gute Idee, den Zeitstempel zum Zeitpunkt der Ausführung zur Protokolldatei oben im Skript hinzuzufügen:
Sie können dann Ihre Fehlermeldungen in die Protokolldatei umleiten
Dadurch wird der Fehler an die Protokolldatei angehängt und die Ausführung fortgesetzt. Wenn Sie die Ausführung stoppen möchten, wenn kritische Fehler auftreten, können Sie
exit
das folgende Skript ausführen :Beachten Sie, dass
exit 1
dass das Programm die Ausführung aufgrund eines nicht angegebenen Fehlers stoppt. Sie können dies anpassen, wenn Sie möchten.Mit diesem Ansatz können Sie Ihre Protokolle anpassen und für jede Komponente Ihres Skripts eine andere Protokolldatei erstellen.
Wenn Sie ein relativ kleines Skript haben oder das Skript eines anderen ausführen möchten, ohne es zu ändern, ist der erste Ansatz besser geeignet.
Wenn Sie immer möchten, dass sich die Protokolldatei am selben Speicherort befindet, ist dies die bessere Option der 2. Auch wenn Sie ein großes Skript mit mehreren Komponenten erstellt haben, möchten Sie möglicherweise jedes Teil anders protokollieren, und der zweite Ansatz ist Ihr einziger Möglichkeit.
quelle
Ich finde es oft nützlich, eine Funktion zur Behandlung von Fehlermeldungen zu schreiben, damit der Code insgesamt sauberer ist.
Dadurch wird der Fehlercode aus dem vorherigen Befehl übernommen und beim Beenden des gesamten Skripts als Standardfehlercode verwendet. Außerdem wird die Uhrzeit mit Mikrosekunden angegeben, sofern dies unterstützt wird (das GNU-Datum
%N
ist Nanosekunden, die wir später auf Mikrosekunden kürzen).Wenn die erste Option Null oder eine positive Ganzzahl ist, wird sie zum Exit-Code und wird aus der Liste der Optionen entfernt. Wir melden die Nachricht dann an den Standardfehler mit dem Namen des Skripts, dem Wort "ERROR" und der Zeit (wir verwenden die Parametererweiterung, um Nanosekunden auf Mikrosekunden abzuschneiden oder für Nicht-GNU-Zeiten, z . B.
12:34:56.%N
um12:34:56
). Nach dem Wort ERROR werden ein Doppelpunkt und ein Leerzeichen hinzugefügt, jedoch nur, wenn eine Fehlermeldung angezeigt wird. Schließlich beenden wir das Skript mit dem zuvor festgelegten Exit-Code und lösen wie gewohnt alle Traps aus.Einige Beispiele (vorausgesetzt, der Code lebt in
script.sh
):quelle