Wie beende ich ein Shell-Skript, wenn ein Teil davon fehlschlägt?

Wie kann ich ein Shell-Skript schreiben, das beendet wird, wenn ein Teil davon fehlschlägt? Wenn beispielsweise das folgende Codefragment fehlschlägt, sollte das Skript beendet werden.

n=0 until [ $n -ge 5 ] do gksu *command* && break n=$[$n+1] sleep 3 

Antwort

Ein Ansatz wäre, set -e am Anfang Ihres Skripts hinzuzufügen. Das bedeutet (von help set):

 -e Exit immediately if a command exits with a non-zero status. 

Wenn also einer Ihrer Befehle fehlschlägt, wird das Skript beendet.

Alternativ können Sie an den möglichen Fehlerpunkten explizite exit -Anweisungen hinzufügen:

command || exit 1 

Kommentare

  • Ich (und das Bash-Wiki ) möchte lieber über die richtige Fehlerbehandlung nachdenken anstatt die (durch Design IMO gebrochen) set -e -Funktion zu verwenden. ' trifft hier jedoch nicht wirklich zu. Das OP möchte das Skript nach 5 fehlgeschlagenen Versuchen beenden, den Befehl auszuführen.
  • @St é phaneChazelas Ich habe '
  • , weil ich ' nicht anders denken kann Frage kann interpretiert werden.
  • @St é phaneChazelas Sie haben vielleicht Recht. Ich habe es wörtlich interpretiert: Wie kann das gesamte Skript beendet werden, wenn ein Teil davon fehlschlägt? Und set -e ist die einzige Möglichkeit, die ich kenne.
  • In diesem Skript-Snipet die Befehle, die set -e ist sleep (break Da es sich um eine spezielle integrierte Funktion handelt, wird das Skript bei einem Fehler in den meisten Shells beendet, Befehle in if oder links von && sind von set -e, n=... könnte fehlschlagen, wenn n schreibgeschützt ist, aber dann würde das Skript auch ohne set -e beendet) Interpretation klingt ziemlich unwahrscheinlich. Ich bin damit einverstanden, dass die Frage schlecht formuliert ist.

Antwort

Sie können ein Skript an jeder Stelle mit dem Schlüsselwort beenden exit. Sie können auch einen Exit-Code angeben, um anderen Programmen anzuzeigen, dass oder wie Ihr Skript fehlgeschlagen ist, z. exit 1 oder exit 2 usw. (Konvention ist Exit-Code 0 für den Erfolg und alles, was größer als 0 ist, bedeutet Fehler, jedoch auch Konvention , Exit-Codes über 127 sind für eine abnormale Beendigung reserviert (z. B. durch ein Signal).

Die generische Konstruktion zum Beenden bei einem Fehler lautet

if [ failure condition ]; then exit n fi 

mit geeigneten failure condition und n. In bestimmten Szenarien können Sie jedoch anders vorgehen. Für Ihren Fall interpretiere ich Ihre Frage, dass Sie beenden möchten, wenn einer der fünf Aufrufe von gksu fehlschlägt. Eine Möglichkeit besteht darin, eine Funktion wie diese

function try_command { for i in 1 2 3 4 5 ; do if gksu command ; then return 0 fi fi exit 1 } 

zu verwenden und dann die Schleife mit try_command aufzurufen.

Es gibt (fortgeschrittenere) oder ausgefeiltere Möglichkeiten, wie Sie Ihre Frage beantworten können. Die obige Lösung ist jedoch für Anfänger zugänglicher als beispielsweise die Lösung von Stephane.

Antwort

attempt=0 until gksu command; do attempt=$((attempt + 1)) if [ "$attempt" -gt 5 ]; then exit 1 fi done 

exit beendet das Skript, sofern es nicht in einer Subshell aufgerufen wird. Wenn sich dieser Teil des Skripts in einer Subshell befindet, z. B. weil er sich innerhalb von (...) oder $(...) oder einem Teil einer Pipeline befindet Dann wird nur diese Unterschale beendet.

Wenn Sie in diesem Fall möchten, dass das Skript zusätzlich zur Unterschale beendet wird, werden Sie “ Ich muss exit aufrufen, wenn diese Subshell beendet wird.

Zum Beispiel hier mit 2 verschachtelten Ebenen von Subshells:

( life=hard output=$( echo blah [ "$life" = easy ] || exit 1 # exit subshell echo blih not run ) || exit # if the subshell exits with a non-zero exit status, # exit as well with the same exit status echo not run either ) || exit # if the subshell exits with a non-zero exit status, # exit as well with the same exit status 

Es kann schwieriger werden, wenn die Subshell Teil einer Pipeline ist. bash verfügt über ein spezielles $PIPESTATUS Array, ähnlich zsh „s $pipestatus eine, die Ihnen hier helfen kann:

{ echo foo exit 1 echo bar } | wc -c subshell_ret=${PIPESTATUS[0]} if [ "$subshell_ret" -ne 0 ]; then exit "$subshell_ret" fi 

Antwort

Trap führt beim Empfang eines Signals eine Aktion aus.

trap "echo EXIT; exit" 0 trap "echo HUP; exit" 1 trap "echo CTL-C; exit" 2 trap "echo QUIT; exit" 3 trap "echo ERR; exit" ERR n=0 until [ $n -ge 5 ] do n=$[$n+1] echo $n sleep 3 done 

Führen Sie dies aus und lassen Sie es normal beenden. Es wird auf Signal 0 abgefangen.

EXIT 

Führen Sie es erneut aus und unterbrechen Sie es mit ^ C. Es fängt sowohl Signal 2 als auch Signal 0 ein.

CTL-C EXIT 

Ein Exit-Status ungleich Null wird bei ERR abgefangen.

ERR EXIT 

Antwort

pass_to_functio() { echo "command exited with status $1" } ( exec <Any Command > & child_pid=$! wait $child_pid pass_to_function $? )& 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.