Ich schreibe ein Skript in Bash, um Code zu testen. Es erscheint jedoch albern, die Tests auszuführen, wenn das Kompilieren des Codes überhaupt fehlschlägt. In diesem Fall werde ich die Tests einfach abbrechen.
Gibt es eine Möglichkeit, dies zu tun, ohne das gesamte Skript in eine while-Schleife zu packen und Pausen zu verwenden? So etwas wie ein Dun Dun Dun Goto?
1
konsequent verwenden. Wenn das Skript von einem anderen Skript ausgeführt werden soll, möchten Sie möglicherweise Ihren eigenen Satz von Statuscodes mit einer bestimmten Bedeutung definieren. Beispiel:1
== Tests fehlgeschlagen,2
== Kompilierung fehlgeschlagen. Wenn das Skript Teil von etwas anderem ist, müssen Sie möglicherweise die Codes anpassen, um sie an die dort verwendeten Praktiken anzupassen. Wenn beispielsweise ein Teil der von automake ausgeführten Testsuite verwendet wird, wird der Code77
zum Markieren eines übersprungenen Tests verwendet.exit #
Befehl wahrscheinlich in eine Funktion, nicht in ein Skript. (In diesem Fallreturn #
stattdessen verwenden.)exit 0
Beenden Sie daher das Skript und geben Sie 0 zurück (und teilen Sie anderen Skripten mit, dass das Ergebnis dieses Skripts erfolgreich sein könnte)Verwenden Sie set -e
Das Skript wird nach der ersten fehlgeschlagenen Zeile beendet (gibt einen Exit-Code ungleich Null zurück). In diesem Fall wird command-that-fail2 nicht ausgeführt.
Wenn Sie den Rückgabestatus jedes einzelnen Befehls überprüfen würden, würde Ihr Skript folgendermaßen aussehen:
Mit set -e würde es so aussehen:
Jeder fehlgeschlagene Befehl führt dazu, dass das gesamte Skript fehlschlägt und einen Exit-Status zurückgibt, den Sie mit $? Überprüfen können . . Wenn Ihr Skript sehr lang ist oder Sie eine Menge Dinge erstellen, wird es ziemlich hässlich, wenn Sie überall Überprüfungen des Rückgabestatus hinzufügen.
quelle
set -e
Sie noch können machen einige Befehle Ausgang mit Fehlern , ohne das Skript zu stoppen:command 2>&1 || echo $?
.set -e
bricht das Skript ab, wenn eine Pipeline- oder Befehlsstruktur einen Wert ungleich Null zurückgibt. Zum Beispielfoo || bar
schlägt nur fehl, wenn beidefoo
und einenbar
Wert ungleich Null zurückgeben. Normalerweise funktioniert ein gut geschriebenes Bash-Skript, wenn Sie esset -e
zu Beginn hinzufügen, und das Hinzufügen funktioniert als automatische Überprüfung der Integrität: Brechen Sie das Skript ab, wenn etwas schief geht.set -o pipefail
Option festlegen.set -e
gerechtmake || exit $?
.set -u
. Werfen Sie einen Blick auf den inoffiziellen Bash-Strict-Modus :set -euo pipefail
.Ein SysOps-Typ hat mir einmal die Drei-Finger-Klauen-Technik beigebracht:
Diese Funktionen sind * NIX OS und Shell-Aroma-robust. Setzen Sie sie an den Anfang Ihres Skripts (Bash oder anders),
try()
Ihre Anweisung und Ihren Code.Erläuterung
(basierend auf dem Kommentar eines fliegenden Schafs ).
yell
: Drucken Sie den Skriptnamen und alle Argumente anstderr
:$0
ist der Pfad zum Skript;$*
sind alle Argumente.>&2
bedeutet,>
stdout zu & pipe umleiten2
. Rohr1
wärestdout
selbst.die
macht das Gleiche wieyell
, wird jedoch mit einem Exit-Status ungleich 0 beendet , was "fehlgeschlagen" bedeutet.try
verwendet den||
(Booleschen WertOR
), der die rechte Seite nur auswertet, wenn die linke fehlgeschlagen ist.$@
ist alles wieder Argumente, aber anders .quelle
$0
ist der Pfad zum Skript.$*
sind alle Argumente.>&2
bedeutet ">
stdout zum&
Rohr umleiten2
". Rohr 1 wäre selbst stdout. so schreien Präfixe alle Argumente mit dem Skriptnamen und Druck auf stderr. Die macht dasselbe wie schreien , beendet sich jedoch mit einem Exit-Status ungleich 0, was "fehlgeschlagen" bedeutet. try verwendet den booleschen Wert oder||
, der die rechte Seite nur auswertet, wenn die linke Seite nicht fehlgeschlagen ist.$@
ist alles wieder Argumente, aber anders . hoffe, das erklärt allesdie() { yell "$1"; exit $2; }
so geändert, dass Sie eine Nachricht übergeben und den Code mit beenden könnendie "divide by zero" 115
.yell
unddie
. Allerdingstry
nicht so sehr. Können Sie ein Beispiel für Ihre Verwendung angeben?Wenn Sie das Skript mit aufrufen
source
, können Sie verwenden,return <x>
wo<x>
sich der Status des Skript-Exits befindet (verwenden Sie einen Wert ungleich Null für Fehler oder Falsch). Wenn Sie jedoch ein ausführbares Skript aufrufen (dh direkt mit seinem Dateinamen), führt die return-Anweisung zu einer Beschwerde (Fehlermeldung "return: kann nur von einer Funktion oder einem Sourcing-Skript" zurückkehren ").Wenn
exit <x>
stattdessen verwendet wird, wird beim Aufrufen des Skriptssource
die Shell beendet, mit der das Skript gestartet wurde. Ein ausführbares Skript wird jedoch wie erwartet beendet.Um beide Fälle im selben Skript zu behandeln, können Sie verwenden
Dies behandelt den jeweils geeigneten Aufruf. Dies setzt voraus, dass Sie diese Anweisung auf der obersten Ebene des Skripts verwenden. Ich würde davon abraten, das Skript direkt aus einer Funktion heraus zu beenden.
Hinweis:
<x>
soll nur eine Zahl sein.quelle
Ich füge oft eine Funktion namens run () hinzu, um Fehler zu behandeln. Jeder Aufruf, den ich tätigen möchte, wird an diese Funktion übergeben, sodass das gesamte Skript beendet wird, wenn ein Fehler auftritt. Dies hat gegenüber der Lösung set -e den Vorteil, dass das Skript nicht stillschweigend beendet wird, wenn eine Zeile ausfällt, und Ihnen das Problem mitteilen kann. Im folgenden Beispiel wird die 3. Zeile nicht ausgeführt, da das Skript beim Aufruf von false beendet wird.
quelle
set -e option
. Dann der Befehl, da es sich um Argumente handelt, habe ich einfache Anführungszeichen verwendet, um Bash-Probleme wie die folgenden zu vermeiden :runTry 'mysqldump $DB_PASS --user="$DB_USER" --host="$BV_DB_HOST" --triggers --routines --events --single-transaction --verbose $DB_SCHEMA $tables -r $BACKUP_DIR/$tables$BACKUP_FILE_NAME'
. Hinweis Ich habe den Namen der Funktion in runTry geändert.eval
ist möglicherweise gefährlich, wenn Sie willkürliche Eingaben akzeptieren, aber ansonsten sieht das ziemlich gut aus.Anstatt zu
if
konstruieren, können Sie die Kurzschlussbewertung nutzen :Beachten Sie das Klammerpaar, das aufgrund der Priorität des Wechseloperators erforderlich ist.
$?
ist eine spezielle Variable, die den Code des zuletzt aufgerufenen Befehls beendet.quelle
command -that --fails || exit $?
es ohne Klammern macheecho $[4/0]
, warum brauchen wir sie dann?echo $[4/0] || exit $?
) Bash wird niemals die ausgeführtecho
, geschweige denn die||
.Ich habe die gleiche Frage, kann sie aber nicht stellen, da es sich um ein Duplikat handelt.
Die akzeptierte Antwort mit exit funktioniert nicht, wenn das Skript etwas komplizierter ist. Wenn Sie einen Hintergrundprozess verwenden, um nach der Bedingung zu suchen, beendet exit nur diesen Prozess, da er in einer Unter-Shell ausgeführt wird. Um das Skript zu beenden, müssen Sie es explizit beenden (zumindest ist dies der einzige Weg, den ich kenne).
Hier ist ein kleines Skript, wie es geht:
Dies ist eine bessere Antwort, aber immer noch unvollständig. Ich weiß wirklich nicht, wie ich den Boom- Teil loswerden soll .
quelle