it-swarm.com.de

Wie kann ich in einem Bash-Skript das gesamte Skript beenden, wenn eine bestimmte Bedingung auftritt?

Ich schreibe ein Skript in Bash, um Code zu testen. Es scheint jedoch dumm zu sein, die Tests auszuführen, wenn das Kompilieren des Codes überhaupt fehlschlägt. In diesem Fall bringe ich die Tests einfach ab.

Gibt es eine Möglichkeit, wie ich dies tun kann, ohne das gesamte Skript in eine while-Schleife zu packen und break zu verwenden? Etwas wie ein Dun Dun Dun Goto?

532
samoz

Versuchen Sie diese Aussage:

exit 1

Ersetzen Sie 1 durch entsprechende Fehlercodes. Siehe auch Exit-Codes mit besonderen Bedeutungen .

583

Verwenden Sie set -e

#!/bin/bash

set -e

/bin/command-that-fails
/bin/command-that-fails2

Das Skript wird nach der ersten fehlgeschlagenen Zeile beendet (gibt den Exit-Code ungleich Null zurück). In diesem Fall wird command-that-fail2 nicht ausgeführt.

Wenn Sie den Rückgabestatus jedes einzelnen Befehls überprüfen würden, würde Ihr Skript folgendermaßen aussehen:

#!/bin/bash

# I'm assuming you're using make

cd /project-dir
make
if [[ $? -ne 0 ]] ; then
    exit 1
fi

cd /project-dir2
make
if [[ $? -ne 0 ]] ; then
    exit 1
fi

Mit set -e würde es so aussehen:

#!/bin/bash

set -e

cd /project-dir
make

cd /project-dir2
make

Bei einem fehlgeschlagenen Befehl schlägt das gesamte Skript fehl und gibt einen Beendigungsstatus zurück, den Sie mit $ überprüfen können. . Wenn Ihr Skript sehr lang ist oder Sie eine Menge Material bauen, wird es ziemlich hässlich, wenn Sie überall Rückgabestatusprüfungen hinzufügen.

607
Shizzmo

Ein böser SysOps-Typ brachte mir einmal die Drei-Finger-Klaue-Technik bei:

yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "[email protected]" || die "cannot $*"; }

Diese Funktionen sind * NIX-Betriebssystem und Shell-Aroma-robust. Setzen Sie sie an den Anfang Ihres Skripts (bash oder anders), try() Ihre Anweisung und den Code.

Erläuterung

(basierend auf fliegendem Schaf Kommentar).

  • yell: Ausdruck des Skriptnamens und aller Argumente an stderr:
    • $0 ist der Pfad zum Skript.
    • $* sind alle Argumente. 
    • >&2 bedeutet > STDOUT AN & PIPE 2 umleiten. pipe 1 wäre selbst stdout
  • die macht dasselbe wie yell, beendet jedoch den Exit-Status non-0, was "fail" bedeutet. 
  • try verwendet den || (boolean OR), der nur dann die rechte Seite auswertet, wenn die linke nicht fehlgeschlagen ist.

Hoffe das erklärt alles.

174
c.gutierrez

Wenn Sie das Skript mit source aufrufen, können Sie return <x> verwenden, wobei <x> der Skript-Exit-Status ist (verwenden Sie einen Wert ungleich Null für Fehler oder falsch). Dies funktioniert auch wie erwartet, wenn Sie das Skript source verwenden. Wenn Sie jedoch ein ausführbares Skript (dh direkt mit dem Dateinamen) aufrufen, führt die return-Anweisung zu einer Beschwerde (Fehlermeldung "return: can only" return von a) Funktion oder Quellenskript ").

Wenn stattdessen exit <x> verwendet wird und das Skript mit source aufgerufen wird, wird die Shell beendet, die das Skript gestartet hat. Ein ausführbares Skript wird jedoch direkt ausgeführt.

Um beide Fälle in demselben Skript zu behandeln, können Sie verwenden

return <x> 2> /dev/null || exit <x>

Dies wird für jeden Aufruf geeignet sein.

Hinweis: <x> soll nur eine Zahl sein.

21
kavadias

Ich füge oft eine Funktion namens run () ein, um Fehler zu behandeln. Jeder Aufruf, den ich ausführen möchte, wird an diese Funktion übergeben, sodass das gesamte Skript beendet wird, wenn ein Fehler auftritt. Der Vorteil gegenüber der set -e-Lösung besteht darin, dass das Skript nicht automatisch beendet wird, wenn eine Zeile ausfällt, und Ihnen das Problem mitteilen kann. Im folgenden Beispiel wird die 3. Zeile nicht ausgeführt, da das Skript beim Aufruf auf false beendet wird.

function run() {
  cmd_output=$(eval $1)
  return_value=$?
  if [ $return_value != 0 ]; then
    echo "Command $1 failed"
    exit -1
  else
    echo "output: $cmd_output"
    echo "Command succeeded."
  fi
  return $return_value
}
run "date"
run "false"
run "date"
10
Joseph Sheedy

Anstelle von if const können Sie die Kurzschlussauswertung verwenden:

#!/usr/bin/env bash

echo $[1+1]
echo $[2/0]              # division by 0 but execution of script proceeds
echo $[3+1]
(echo $[4/0]) || exit $? # script halted with code 1 returned from `echo`
echo $[5+1]

Beachten Sie das Klammerpaar, das aufgrund der Priorität des Wechseloperators erforderlich ist. $? ist eine spezielle Variable, die den Beendigungscode des zuletzt aufgerufenen Befehls setzt.

5
skalee

Ich habe dieselbe Frage, kann sie aber nicht stellen, weil es ein Duplikat wäre.

Die akzeptierte Antwort mit exit funktioniert nicht, wenn das Skript etwas komplizierter ist. Wenn Sie einen Hintergrundprozess verwenden, um die Bedingung zu überprüfen, beendet Exit diesen Prozess nur, da er in einer Sub-Shell ausgeführt wird. Um das Skript zu beenden, müssen Sie es explizit abtöten (zumindest weiß ich es auf diese Weise).

Hier ist ein kleines Skript, wie es geht:

#!/bin/bash

boom() {
    while true; do sleep 1.2; echo boom; done
}

f() {
    echo Hello
    N=0
    while
        ((N++ <10))
    do
        sleep 1
        echo $N
        #        ((N > 5)) && exit 4 # does not work
        ((N > 5)) && { kill -9 $$; exit 5; } # works 
    done
}

boom &
f &

while true; do sleep 0.5; echo beep; done

Dies ist eine bessere Antwort, aber immer noch unvollständig. Ich weiß wirklich nicht, wie ich den boomTeil loswerden kann.

0
Gyro Gearloose