613 Stimmen

Abbruch eines Shell-Skripts, wenn ein Befehl einen Wert ungleich Null zurückgibt

Ich habe ein Bash-Shell-Skript, das eine Reihe von Befehlen aufruft.

Ich möchte, dass das Shell-Skript automatisch mit einem Rückgabewert von 1 beendet wird, wenn einer der Befehle einen Wert ungleich Null zurückgibt.

Ist dies möglich, ohne das Ergebnis jedes Befehls explizit zu überprüfen?

Zum Beispiel,

dosomething1
if [[ $? -ne 0 ]]; then
    exit 1
fi

dosomething2
if [[ $? -ne 0 ]]; then
    exit 1
fi

976voto

Ville Laurikari Punkte 27255

Fügen Sie dies am Anfang des Skripts ein:

set -e

Dies führt dazu, dass die Shell sofort beendet wird, wenn ein einfacher Befehl mit einem Exit-Wert ungleich Null beendet wird. Ein einfacher Befehl ist jeder Befehl, der nicht Teil eines if-, while- oder until-Tests oder Teil einer &&- oder ||-Liste ist.

Siehe die bash(1) man-Seite über den internen Befehl "set" für weitere Einzelheiten.

Ich persönlich starte fast alle Shell-Skripte mit "set -e". Es ist wirklich ärgerlich, wenn ein Skript stur weiterläuft, wenn etwas in der Mitte fehlschlägt und die Annahmen für den Rest des Skripts unterbricht.

274voto

leonbloy Punkte 68836

Um die akzeptierte Antwort zu ergänzen:

Bitte beachten Sie, dass set -e ist manchmal nicht genug, vor allem, wenn Sie Rohre haben.

Nehmen wir zum Beispiel an, Sie haben dieses Skript

#!/bin/bash
set -e 
./configure  > configure.log
make

... was wie erwartet funktioniert: ein Fehler in configure bricht die Ausführung ab.

Morgen nehmen Sie eine scheinbar unbedeutende Änderung vor:

#!/bin/bash
set -e 
./configure  | tee configure.log
make

... und jetzt funktioniert es nicht mehr. Dies wird erklärt aquí und ein Workaround (nur Bash) wird bereitgestellt:

#!/bin/bash
set -e 
**set -o pipefail**

./configure  | tee configure.log
make

105voto

Zan Lynx Punkte 51045

Die if-Anweisungen in Ihrem Beispiel sind unnötig. Machen Sie es einfach so:

dosomething1 || exit 1

Wenn Sie den Rat von Ville Laurikari befolgen und die set -e dann müssen Sie für einige Befehle dies verwenden:

dosomething || true

Le site || true bewirkt, dass die Befehlspipeline eine true Rückgabewert, auch wenn der Befehl fehlschlägt, so dass die -e Option wird das Skript nicht beendet.

30voto

Nails N. Punkte 551

Wenn Sie beim Verlassen des Programms Aufräumarbeiten durchführen müssen, können Sie auch 'trap' mit dem Pseudo-Signal ERR verwenden. Dies funktioniert genauso wie das Abfangen von INT oder jedem anderen Signal; die Bash wirft ERR, wenn ein Befehl mit einem Wert ungleich Null beendet wird:

# Create the trap with   
#    trap COMMAND SIGNAME [SIGNAME2 SIGNAME3...]
trap "rm -f /tmp/$MYTMPFILE; exit 1" ERR INT TERM
command1
command2
command3
# Partially turn off the trap.
trap - ERR
# Now a control-C will still cause cleanup, but
# a nonzero exit code won't:
ps aux | grep blahblahblah

Oder, vor allem, wenn Sie "set -e" verwenden, könnten Sie EXIT trappen; Ihr Trap wird dann ausgeführt, wenn das Skript aus irgendeinem Grund beendet wird, einschließlich eines normalen Endes, einer Unterbrechung, eines durch die Option -e verursachten Endes usw.

18voto

Mark Edgar Punkte 4467

Le site $? wird nur selten benötigt. Das Pseudo-Idiom command; if [ $? -eq 0 ]; then X; fi sollte immer geschrieben werden als if command; then X; fi .

Die Fälle, in denen $? ist erforderlich, wenn mehrere Werte miteinander verglichen werden müssen:

command
case $? in
  (0) X;;
  (1) Y;;
  (2) Z;;
esac

oder wenn $? wiederverwendet oder anderweitig manipuliert werden muss:

if command; then
  echo "command successful" >&2
else
  ret=$?
  echo "command failed with exit code $ret" >&2
  exit $ret
fi

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X