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?

War es hilfreich?

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

  1. Wie erhalte ich den Exit-Code von cmd1 in cmd1|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 in

    cmd | head -1
    

    Sie könnten einen 141 (oder 269 mit ksh93) Exit-Status von cmd1 beobachten, aber es ist, weil cmd durch ein SIGPIPE Signal unterbrochen wurde, wenn head -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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top