it-swarm.com.de

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
58
Weylyn

Ein Ansatz wäre, set -e an den Anfang Ihres Skripts. Das heißt (von help set):

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

Wenn 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
98
terdon

Sie können ein Skript an jeder Stelle mit dem Schlüsselwort exit beenden. 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. (Konventionell ist der Exit-Code 0 für den Erfolg und alles, was größer als 0 ist, bedeutet einen Fehler. Allerdings sind Exit-Codes über 127 auch konventionell für eine abnormale Beendigung reserviert (z. B. durch ein Signal).).

Die generische Konstruktion, die bei einem Fehler beendet werden soll, lautet

if [ failure condition ]; then
    exit n
fi

mit passendem 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 solche Funktion zu verwenden

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

und rufen Sie dann die Schleife mit try_command.

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.

17
countermode
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. Befindet sich dieser Teil des Skripts in einer Subshell, z. B. weil er sich innerhalb von (...) Oder $(...) oder einem Teil einer Pipeline befindet, wird er nur beendet diese Unterschale .

In diesem Fall müssen Sie exit aufrufen, wenn das Skript zusätzlich zur Unterschale beendet werden soll Unterschale verlassen.

Zum Beispiel hier mit 2 verschachtelten Ebenen von Unterschalen:

(
  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 hat ein spezielles $PIPESTATUS Array, ähnlich dem $pipestatus von zsh, das 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
11

Die Falle 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 fängt das Signal 0 ein.

EXIT

Führen Sie es erneut aus und unterbrechen Sie 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
3
RobP