Beenden Sie Shell-Skript auf Basis von Prozessexitcode
Frage
Ich habe einen Shell-Skript, das eine Reihe von Befehlen ausführt. Wie mache ich die Shell-Skript beendet, wenn einer der Befehle Ausgang mit einem Nicht-Null-Exit-Code?
Lösung
Nach jedem Befehl kann der Exit-Code in der $?
Variable gefunden werden, so dass Sie so etwas wie haben würden:
ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
Sie müssen vorsichtig verrohrt Befehle sein, da nur die $?
Sie den Return-Code des letzten Elements in dem Rohr gibt so im Code:
ls -al file.ext | sed 's/^/xx: /"
wird nicht einen Fehlercode zurück, wenn die Datei nicht existiert (da der sed
Teil der Pipeline tatsächlich funktioniert, Rückkehr 0).
Der bash
Shell stellt tatsächlich eine Anordnung, die in diesem Fall unterstützen kann, dass sein PIPESTATUS
. Dieses Array hat ein Element für jede der Pipeline-Komponenten, die Sie individuell wie ${PIPESTATUS[0]}
zugreifen können:
pax> false | true ; echo ${PIPESTATUS[0]}
1
Beachten Sie, dass dies das Ergebnis des false
Befehl bekommen, nicht die gesamte Pipeline. Sie können auch die gesamte Liste erhalten zu verarbeiten, wie Sie sehen, passen:
pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1
Wenn Sie den größten Fehlercode aus einer Pipeline bekommen wollen, Sie so etwas wie verwenden:
true | true | false | true | false
rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done
echo $rc
Das geht durch jede der PIPESTATUS
Elemente wiederum in rc
speichern, wenn es größer als der vorherige rc
Wert war.
Andere Tipps
Wenn Sie mit $ arbeiten wollen ?, werden Sie es nach jedem Befehl überprüfen müssen, da $? wird nach jedem Befehl beendet aktualisiert. Das bedeutet, dass, wenn Sie eine Pipeline ausführen, werden Sie nur den Exit-Code des letzten Prozesses in der Pipeline erhalten.
Ein weiterer Ansatz ist, dies zu tun:
set -e
set -o pipefail
Wenn Sie dies an der Spitze des Shell-Skript setzen, sieht es aus wie bash wird für Dich darum kümmern. Als vorher bereits erwähnt, „set -e“ wird bash verursachen mit einem Fehler an einem einfachen Befehl zu beenden. „Set -o pipefail“ wird heftigen Schlag verursacht mit einem Fehler auf einem beliebigen Befehl zu beenden und in einer Rohrleitung.
Siehe hier oder hier für ein wenig mehr Diskussion über dieses Problem. Hier ist der Bash-Abschnitt zu dem Satz builtin.
„set -e
“ ist wahrscheinlich der einfachste Weg, dies zu tun. setzen, dass kurz vor allen Befehlen in Ihrem Programm.
Wenn Sie nur Ausfahrt in der Bash ohne Parameter aufrufen, wird es den Exit-Code des letzten Befehls zurück. In Kombination mit OR die bash sollte nur Exit aufrufen, wenn der vorherige Befehl fehlschlägt. Aber ich habe nicht getestet.
command1 || exit; command2 || exit;
Die Bash speichert auch den Exit-Code des letzten Befehl in der Variablen $ ?.
[ $? -eq 0 ] || exit $?; # exit for none-zero return code
http://cfaj.freeshell.org/shell/cus- faq-2.html # 11
-
Wie erhalte ich den Exit-Code von
cmd1
incmd1|cmd2
Beachten Sie zunächst, dass
cmd1
Exit-Code ungleich Null sein könnte und noch nicht tun bedeutet einen Fehler. Dies geschieht zum Beispiel incmd | head -1
Sie könnten einen 141 (oder 269 mit ksh93) Exit-Status von
cmd1
beobachten, aber es ist, weilcmd
durch ein SIGPIPE Signal unterbrochen wurde, wennhead -1
beendet, nachdem eine Zeile gelesen zu haben.Um den Exit-Status der Elemente einer Pipeline kennen
cmd1 | cmd2 | cmd3
a. mit zsh:
Die Exit-Codes sind in der PIPESTATUS speziellen Anordnung vorgesehen.
cmd1
Exit-Code ist in$pipestatus[1]
,cmd3
Exit-Code in$pipestatus[3]
, so dass$?
ist immer gleich$pipestatus[-1]
.b. mit bash:
Die Exit-Codes sind in der
PIPESTATUS
speziellen Anordnung vorgesehen.cmd1
Exit-Code ist in${PIPESTATUS[0]}
,cmd3
Exit-Code in${PIPESTATUS[2]}
, so dass$?
ist immer gleich${PIPESTATUS: -1}
....
Weitere Informationen finden Sie in den folgenden Link href="http://cfaj.freeshell.org/shell/cus-faq-2.html#11".
für bash:
# this will trap any errors or commands with non-zero exit status
# by calling function catch_errors()
trap catch_errors ERR;
#
# ... the rest of the script goes here
#
function catch_errors() {
# do whatever on errors
#
#
echo "script aborted, because of errors";
exit 0;
}
In der bash so einfach ist, nur um sie mit && bindet zusammen:
command1 && command2 && command3
Sie können auch die verschachtelte if-Konstrukt verwenden:
if command1
then
if command2
then
do_something
else
exit
fi
else
exit
fi
#
#------------------------------------------------------------------------------
# run a command on failure exit with message
# doPrintHelp: doRunCmdOrExit "$cmd"
# call by:
# set -e ; doRunCmdOrExit "$cmd" ; set +e
#------------------------------------------------------------------------------
doRunCmdOrExit(){
cmd="$@" ;
doLog "DEBUG running cmd or exit: \"$cmd\""
msg=$($cmd 2>&1)
export exit_code=$?
# if occured during the execution exit with error
error_msg="Failed to run the command:
\"$cmd\" with the output:
\"$msg\" !!!"
if [ $exit_code -ne 0 ] ; then
doLog "ERROR $msg"
doLog "FATAL $msg"
doExit "$exit_code" "$error_msg"
else
#if no errors occured just log the message
doLog "DEBUG : cmdoutput : \"$msg\""
doLog "INFO $msg"
fi
}
#eof func doRunCmdOrExit