webentwicklung-frage-antwort-db.com.de

Abbrechen 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 dem Rückgabewert 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?

z.B.

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

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

Fügen Sie dies am Anfang des Skripts hinzu:

set -e

Dadurch wird die Shell sofort beendet, wenn ein einfacher Befehl mit einem Exit-Wert ungleich Null beendet wird. Ein einfacher Befehl ist ein beliebiger Befehl, der nicht Teil eines if, while oder until-Tests oder Teil eines && oder || ist Liste.

Weitere Informationen finden Sie in der Manpage bash (1) zum internen Befehl "set".

Ich persönlich starte fast alle Shell-Skripte mit "set -e". Es ist wirklich ärgerlich, wenn ein Skript hartnäckig weiterarbeitet, wenn etwas in der Mitte versagt und die Annahmen für den Rest des Skripts verletzt.

676
Ville Laurikari

So fügen Sie der akzeptierten Antwort hinzu:

Bedenke, dass set -e reicht manchmal nicht aus, besonders wenn Sie Pfeifen haben.

Angenommen, 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 triviale Änderung vor:

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

... und jetzt klappt es nicht. Dies wird erklärt hier , und es wird eine Problemumgehung (nur Bash) bereitgestellt:

 #!/bin/bash 
 set -e 
set -o pipefail
 
 ./ configure | tee configure.log 
 make 
186
leonbloy

Die if-Anweisungen in Ihrem Beispiel sind nicht erforderlich. Mach es einfach so:

dosomething1 || exit 1

Wenn Sie den Rat von Ville Laurikari befolgen und set -e Verwenden, müssen Sie für einige Befehle möglicherweise Folgendes eingeben:

dosomething || true

Mit || true Erhält die Befehlspipeline einen true -Rückgabewert, auch wenn der Befehl fehlschlägt, sodass die Option -e Das Skript nicht beendet.

77
Zan Lynx

Wenn Sie beim Beenden eine Bereinigung durchführen müssen, können Sie auch 'trap' mit dem Pseudosignal ERR verwenden. Dies funktioniert genauso wie das Abfangen von INT oder anderen Signalen. bash löst ERR aus, 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, besonders wenn Sie "set -e" verwenden, können Sie EXIT abfangen. Ihre Trap wird dann ausgeführt, wenn das Skript aus irgendeinem Grund beendet wird, einschließlich eines normalen Endes, Interrupts, eines durch die Option -e verursachten Exits usw.

27
fholo

Führen Sie es mit -e oder set -e oben.

Siehe auch set -u.

12
lumpynose

Das $? Variable wird 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 $? wird benötigt, wenn es gegen mehrere Werte geprüft werden soll:

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

oder wann $? muss wiederverwendet oder anderweitig manipuliert werden:

if command; then
  echo "command successful" >&2
else
  ret=$?
  echo "command failed with exit code $ret" >&2
  exit $ret
fi
11
Mark Edgar
#!/bin/bash -e

sollte ausreichen.

3
Baligh Uddin

Ein Ausdruck wie

dosomething1 && dosomething2 && dosomething3

beendet die Verarbeitung, wenn einer der Befehle einen Wert ungleich Null zurückgibt. Der folgende Befehl gibt beispielsweise niemals "erledigt" aus:

cat nosuchfile && echo "done"
echo $?
1
3
gabor