So überprüfen Sie den Exit-Status mithilfe einer if-Anweisung

255

Ich habe mich gefragt, wie ich den Exit-Status in einer if-Anweisung am besten überprüfen kann, um eine bestimmte Ausgabe wiederzugeben.

Ich denke daran

if [ $? -eq 1 ]
then
   echo "blah blah blah"
fi

Das Problem, das ich auch habe, ist, dass die exit-Anweisung vor der if-Anweisung steht, nur weil sie diesen Exit-Code haben muss. Außerdem weiß ich, dass ich etwas falsch mache, da der Exit das Programm offensichtlich beenden würde.

deadcell4
quelle
3
Bitte veröffentlichen Sie Ihr komplettes Skript (oder zumindest einen breiteren Bereich). Sonst scheint das in Ordnung zu sein.
RedX
5
Wenn Sie den Exit-Code eines bestimmten Programmaufrufs an zwei verschiedenen Stellen verwenden müssen, müssen Sie ihn beibehalten - etwas in der Art vonsome_program; rc=$?; if [ ${rc} -eq 1 ] .... fi ; exit ${rc}
Twalberg

Antworten:

262

Jeder ausgeführte Befehl hat einen Exit-Status.

Bei dieser Überprüfung wird der Beendigungsstatus des Befehls überprüft, der zuletzt beendet wurde, bevor diese Zeile ausgeführt wird.

Wenn Sie möchten, dass Ihr Skript beendet wird, wenn dieser Test true zurückgibt (der vorherige Befehl ist fehlgeschlagen), setzen Sie exit 1(oder was auch immer) ifnach dem in diesen Blockecho .

Wenn Sie den Befehl ausführen und seine Ausgabe mit den folgenden Methoden testen möchten, ist dies häufig einfacher.

if some_command; then
    echo command returned true
else
    echo command returned some error
fi

Oder zu drehen, der um den Einsatz !für die Negation

if ! some_command; then
    echo command returned some error
else
    echo command returned true
fi

Beachten Sie aber , dass keiner von diesen Sorgen , was der Fehlercode ist. Wenn Sie wissen, dass Sie sich nur um einen bestimmten Fehlercode kümmern, müssen Sie dies $?manuell überprüfen .

Etan Reisner
quelle
11
@ deadcell4 Wenn man ein Shell-Skript bei einem Programmfehler beenden muss, ist die folgende Redewendung nützlicha_command || return 1
gboffi
10
@gboffi returnfunktioniert nur in einer Funktion und einem Sourcing-Skript. Sie benötigen exitfür den anderen Fall (der in einer Funktion und einem Sourcing-Skript zu viel bewirkt). Aber ja, das ist sicherlich ein vernünftiges Muster, wenn Sie keine spezielle Bereinigung oder zusätzliche Ausgabe benötigen.
Etan Reisner
1
Ich muss sagen, dass dashdie standardmäßige nicht interaktive Shell in vielen modernen Linux-Distributionen die Unterscheidung zwischen returnund exitinnerhalb von ausgeführten Shell-Skripten nicht berücksichtigt. dashBeendet das Skript, auch wenn ich returnes verwende.
Gboffi
Welche Logik steckt hinter den letzten beiden Überprüfungen? Es scheint nicht intuitiv zu sein, dass die Bedingung erfüllt ist, if <command>wenn der Exit-Code 0 ist. In jeder anderen Sprache wäre es umgekehrt
sjw
3
WICHTIGER HINWEIS: Dies funktioniert nicht bei Rohren. if ! some_command | some_other_commandignoriert den Status von some_command. Die zwei häufigsten Problemumgehungen für Befehle sind: set -o pipefail(kann die Funktionalität in anderen Teilen Ihres Programms ändern) oder das Verschieben der ifAnweisung if [[ ${PIPESTATUS[0]} -ne 0 ]]als separater Folgebefehl (hässlich, aber funktional). Wenn Sie verwenden, set -emöchten Sie || truebei Verwendung der zweiten Lösung auch das Rohrende erweitern, da das Entfernen des Rohrs aus dem von angebotenen Kontrollfluss ifandernfalls dazu führen würde, dass es sofort austritt.
Alex Jansen
186

Beachten Sie, dass Exit-Codes! = 0 verwendet werden, um Fehler zu melden. Also ist es besser zu tun:

retVal=$?
if [ $retVal -ne 0 ]; then
    echo "Error"
fi
exit $retVal

anstatt

# will fail for error codes > 1
retVal=$?
if [ $retVal -eq 1 ]; then
    echo "Error"
fi
exit $retVal
Oo.oO
quelle
Sie müssen auf retVal testen, weil $? Nach der Zuweisung von retVal ist nicht der Rückgabewert von Ihrem Befehl.
anr78
Nicht wirklich: mywiki.wooledge.org/BashFAQ/002 - ich stimme jedoch zu, dass das Bearbeiten die Lesbarkeit verbessert.
Oo.oO
1
Habe
anr78
dnf check-updateGibt 0 (keine Updates), 100 (Updates verfügbar) oder 1 (Fehler) zurück.
JWW
1
@jww - Nun, das ist keine gute Idee, gegen die Konvention zu verstoßen ( gnu.org/software/bash/manual/html_node/Exit-Status.html ). Aber nichts kann das verhindern. Wenn dnfEntwickler diesen Weg gewählt haben, ist es ihre Wahl. Aber dennoch macht ihre Wahl nicht die Spezifikation gebrochen :)
Oo.oO
44

$?ist ein Parameter wie jeder andere. Sie können den zu verwendenden Wert speichern, bevor Sie schließlich aufrufen exit.

exit_status=$?
if [ $exit_status -eq 1 ]; then
    echo "blah blah blah"
fi
exit $exit_status
chepner
quelle
29

Alternative zu explizit if Aussage

Minimal:

test $? -eq 0 || echo "something bad happened"

Komplett:

EXITCODE=$?
test $EXITCODE -eq 0 && echo "something good happened" || echo "something bad happened"; 
exit $EXITCODE
Catskul
quelle
13

Nur um die hilfreiche und detaillierte Antwort zu ergänzen :

Wenn Sie den Exit-Code explizit überprüfen müssen, ist es besser, den arithmetischen Operator folgendermaßen zu verwenden (( ... )):

run_some_command
(($? != 0)) && { printf '%s\n' "Command exited with non-zero"; exit 1; }

Oder verwenden Sie eine caseAnweisung:

run_some_command; ec=$?  # grab the exit code into a variable so that it can
                         # be reused later, without the fear of being overwritten
case $ec in
    0) ;;
    1) printf '%s\n' "Command exited with non-zero"; exit 1;;
    *) do_something_else;;
esac

Verwandte Antwort zur Fehlerbehandlung in Bash:

Codeforester
quelle