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 ' gewonnen Ich diskutiere nicht mit Ihnen darüber, ob ' defekt ist. Ich bin sicher, dass Sie ' re richtig. Das OP fragte jedoch " Wie kann ich ein Shell-Skript schreiben, das beendet wird, wenn ein Teil davon fehlschlägt? ", was macht Sie aus? Denken Sie, es geht ' darum, nach 5 Fehlern zu beenden?
- , 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
istsleep
(break
Da es sich um eine spezielle integrierte Funktion handelt, wird das Skript bei einem Fehler in den meisten Shells beendet, Befehle inif
oder links von&&
sind vonset -e
,n=...
könnte fehlschlagen, wennn
schreibgeschützt ist, aber dann würde das Skript auch ohneset -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 $? )&