849 Stimmen

Automatisches Beenden von Bash-Shell-Skripten bei Fehlern

Ich habe einige Shell-Skripte geschrieben, und ich fände es nützlich, wenn es die Möglichkeit gäbe, die Ausführung des besagten Shell-Skripts anzuhalten, wenn einer der Befehle fehlschlägt. Siehe unten für ein Beispiel:

#!/bin/bash

cd some_dir

./configure --some-flags

make

make install

Wenn das Skript also in diesem Fall nicht in das angegebene Verzeichnis wechseln kann, dann würde es sicher nicht eine ./konfigurieren nachher, wenn sie fehlschlägt.

Ich bin mir bewusst, dass ich für jeden Befehl eine if-Prüfung durchführen könnte (was ich für eine hoffnungslose Lösung halte), aber gibt es eine globale Einstellung, die das Skript beendet, wenn einer der Befehle fehlschlägt?

2 Stimmen

Die Antwort geht an Adam für die Details zu set -e (was genau erwünscht ist). Dank auch an a_m0d für die Info über Fallen (obwohl nicht 100% relevant).

2 Stimmen

Gelten diese Antworten für sh genau so wie bash ?

24voto

Matthew Flaschen Punkte 266507

Eine Redewendung lautet:

cd some_dir && ./configure --some-flags && make && make install

Mir ist klar, dass das lang werden kann, aber bei größeren Skripten könnten Sie es in logische Funktionen aufteilen.

19voto

a_m0d Punkte 11764

Ich denke, was Sie suchen, ist die trap Befehl:

trap command signal [signal ...]

Weitere Informationen finden Sie unter diese Seite .

Eine weitere Möglichkeit ist die Verwendung der set -e Befehl am Anfang Ihres Skripts - er bewirkt, dass das Skript beendet wird, wenn ein Programm/Befehl einen Wert zurückgibt, der nicht wahr ist.

17voto

Inian Punkte 70880

Ein Punkt, der in den vorhandenen Antworten fehlt, ist die Vererbung der Fehlerfallen. Die bash Shell bietet eine solche Option für die Verwendung von set

-E

Wenn sie aufgestellt ist, wird jede Falle auf ERR wird an Shell-Funktionen, Befehlssubstitutionen und Befehle vererbt, die in einer Subshell-Umgebung ausgeführt werden. Die ERR Falle ist normalerweise no in solchen Fällen vererbt.


Adam Rosenfields Antwort Empfehlung zur Verwendung set -e ist in bestimmten Fällen richtig, hat aber seine eigenen potenziellen Fallstricke. Siehe GreyCat's BashFAQ - 105 - Warum macht set -e (oder set -o errexit, oder trap ERR) nicht das, was ich erwartet habe?

Dem Handbuch zufolge verlässt set -e

wenn ein einfacher Befehl mit einem Status ungleich Null beendet wird. Die Shell wird nicht beendet, wenn der fehlgeschlagene Befehl Teil der Befehlsliste ist, die unmittelbar auf einen while o until Schlüsselwort, Teil der test in a if statement , Teil eines && o || Liste mit Ausnahme des Befehls nach dem final && or || , any command in a pipeline but the last oder wenn der Rückgabewert des Befehls über ! ".

was bedeutet, set -e funktioniert in den folgenden einfachen Fällen nicht (detaillierte Erklärungen finden Sie im Wiki)

  1. Verwendung des arithmetischen Operators let o $((..)) ( bash 4.1 ff), um einen Variablenwert zu erhöhen als

    #!/usr/bin/env bash
    set -e
    i=0
    let i++                   # or ((i++)) on bash 4.1 or later
    echo "i is $i" 
  2. Wenn der beanstandete Befehl no Teil des letzten Befehls, der über && o || . Zum Beispiel würde die folgende Falle nicht auslösen, wenn sie es sollte

    #!/usr/bin/env bash
    set -e
    test -d nosuchdir && echo no dir
    echo survived
  3. Bei falscher Verwendung in einer if Anweisung als, der Exit-Code der if Anweisung ist der Exit-Code des zuletzt ausgeführten Befehls. Im folgenden Beispiel war der zuletzt ausgeführte Befehl echo die die Falle nicht auslösen würde, obwohl die test -d gescheitert

    #!/usr/bin/env bash
    set -e
    f() { if test -d nosuchdir; then echo no dir; fi; }
    f 
    echo survived
  4. Bei der Verwendung mit Befehlssubstitution werden sie ignoriert, es sei denn inherit_errexit wird eingestellt mit bash 4.4

    #!/usr/bin/env bash
    set -e
    foo=$(expr 1-1; true)
    echo survived
  5. wenn Sie Befehle verwenden, die wie Zuweisungen aussehen, aber keine sind, wie z. B. export , declare , typeset o local . Hier der Funktionsaufruf an f sera no Ausgang als local hat den zuvor eingestellten Fehlercode gekehrt.

    set -e
    f() { local var=$(somecommand that fails); }        
    g() { local var; var=$(somecommand that fails); }
  6. Wenn der Befehl in einer Pipeline verwendet wird und der verletzende Befehl no Teil des letzten Befehls. So würde z.B. der unten stehende Befehl trotzdem ausgeführt werden. Eine Möglichkeit ist die Aktivierung von pipefail durch Rückgabe des Exit-Codes der erste gescheiterten Prozess:

    set -e
    somecommand that fails | cat -
    echo survived

Die ideale Empfehlung lautet no verwenden. set -e und implementieren Sie stattdessen eine eigene Version der Fehlerprüfung. Weitere Informationen zur Implementierung einer eigenen Fehlerbehandlung finden Sie in einer meiner Antworten auf Fehler in einem Bash-Skript auslösen

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X