Wie überprüfe ich, ob ein Befehl erfolgreich war?

234

Gibt es eine Möglichkeit zu überprüfen, ob bei der Ausführung eines Befehls ein Fehler vorliegt?

Beispiel

test1=`sed -i "/:@/c connection.url=jdbc:oracle:thin:@$ip:1521:$dataBase" $search`
valid $test1

function valid () {
  if $test -eq 1; then
    echo "OK"
    else echo "ERROR" 
  fi
}

Ich habe es bereits versucht, aber es scheint nicht zu funktionieren. Ich weiß nicht, wie das geht.

moata_u
quelle
9
Bevorzugen Sie $ (foo) gegenüber backticks `foo` , da Sie es verschachteln können und es einfacher ist, zwischen Apostrophen zu unterscheiden.
Benutzer unbekannt
1
Übrigens müssen Sie eine Funktion ( valid) definieren, bevor Sie sie aufrufen.
wjandrea
Siehe auch
Eliah Kagan

Antworten:

344

Der Rückgabewert wird in gespeichert $?. 0 zeigt Erfolg an, andere zeigen Fehler an.

some_command
if [ $? -eq 0 ]; then
    echo OK
else
    echo FAIL
fi

Wie bei jedem anderen Textwert können Sie ihn zum späteren Vergleich in einer Variablen speichern:

some_command
retval=$?
do_something $retval
if [ $retval -ne 0 ]; then
    echo "Return code was not zero but $retval"
fi

Mögliche Vergleichsoperatoren finden Sie unter man test.

Lekensteyn
quelle
Das ist schön ... kann ich den Ausgabefehler halten ?? !! , weil ich in diesem Fall 2 Fehler habe: Befehlsfehler "Text" ex, Datei nicht gefunden und mein Fehler "Text" Was in diesem Fall zum Beispiel fehlgeschlagen ist
moata_u
@moata_u: Sie können den Wert in einer Variablen speichern, wie in meiner Antwort gezeigt.
Lekensteyn
@moata_u: Sie müssen ein ;vor das elseund setzen fi: `if ...; dann ...; sonst ...; fi
Lekensteyn
4
Dies ist eine nutzlose Verwendung vontest .
David Foerster
1
@Blauhirn [ $? ](oder gleichwertig test $?) funktioniert nicht, da $?es eine Zahl (0, 1 usw.) ergibt, die nicht null ist. In den Dokumenten finden Sie folgende Informationentest : "Wenn EXPRESSION weggelassen wird, gibt 'test' false zurück. Wenn EXPRESSION ein einzelnes Argument ist, gibt 'test' false zurück, wenn das Argument null ist, und andernfalls true."
Lekensteyn
87

Wenn Sie nur wissen müssen, ob der Befehl erfolgreich war oder fehlgeschlagen ist, testen Sie ihn nicht, sondern testen Sie ihn $?direkt. Z.B:

if some_command; then
    printf 'some_command succeeded\n'
else
    printf 'some_command failed\n'
fi

Und das Zuweisen der Ausgabe zu einer Variablen ändert den Rückgabewert nicht (nun, es sei denn, es verhält sich anders, wenn stdout natürlich kein Terminal ist).

if output=$(some_command); then
    printf 'some_command succeded, the output was «%s»\n' "$output"
fi

http://mywiki.wooledge.org/BashGuide/TestsAndConditionals erklärt ifgenauer.

geirha
quelle
Was ist, wenn Sie etwas anderes als Verzweigen tun möchten, wie das Speichern des Booleschen Werts, ob er fehlgeschlagen ist oder nicht, in einer INI? Dann tut dies Ihre Ausgabevariable nicht, aber $?Sie sagen zu Unrecht, dass das direkte Testen des Befehls strikt besser ist.
Timothy Swan
Die Ausgabe an eine variable Zuweisung kann den Rückgabewert ändern , wenn man verwendet localBefehl, dh local foo=$(false); echo $?;erzeugt 0am Ausgang. Ist localaber nur innerhalb von Bash-Funktionen relevant.
Cromax
26
command && echo OK || echo Failed
Abraham Sanchez
quelle
Wenn ein commandFehler auf dem Bildschirm angezeigt wird, wie kann er ausgeblendet werden?
Sigur
Wenn Sie commandFehler in stderr ausschreiben, können Sie das Formular verwenden command 2> /dev/null && echo OK || echo Failed. Der 2> /dev/nullleitet die stderr-Ausgabe weiter an /dev/null. Einige Dienstprogramme schreiben jedoch Fehler in stdout (obwohl dies keine gute Vorgehensweise ist). In diesem Fall können Sie die 2 in der Umleitung weglassen, verlieren jedoch alle Ausgaben des Befehls. Diese Methode zur Erfolgskontrolle eignet sich für einfache ternäre Logik, für komplexere Verhalten ist es jedoch am besten, die $?Erfolgskontrolle für Befehle ifdurchzuführen oder die in der Antwort von @ geirha beschriebene Blockmethode zu verwenden.
Bender the Greatest
17

$? sollte den Exit-Status des vorherigen Befehls enthalten, der null sein sollte, damit kein Fehler auftritt.

So etwas wie;

cd /nonexistant
if [ $? -ne 0 ]
then
    echo failed
else
    echo success!
fi

In den meisten Fällen ist es einfacher, Befehle, die voneinander abhängig sein müssen, mit dem Konstrukt && zu verketten. So cd /nonexistant && echo success!würde nicht echo Erfolg , weil der Befehl bricht vor &&. Die Konsequenz daraus ist ||, wo cd /nonexistant || echo fail das Echo fehlschlagen würde , weil die CD fehlgeschlagen ist. (Dies ist nützlich, wenn Sie beispielsweise || exit verwenden, wodurch das Skript beendet wird, wenn der vorherige Befehl fehlgeschlagen ist.)

Shaun
quelle
Das ist schön ... kann ich den Ausgabefehler halten ?? !! , weil ich in diesem Fall 2 Fehler habe: Befehlsfehler "Text" ex, Datei nicht gefunden und mein Fehler "Text" Was in diesem Fall zum Beispiel fehlgeschlagen ist
moata_u
@moata_u, siehe mywiki.wooledge.org/BashFAQ/002
geirha
5
command && echo $? || echo $?
modrobert
quelle
Du meinst command; echo $??
Javier Buzzi
Nein, meine Zeile ist korrekt. Sie gibt den tatsächlichen Ergebniscode als Zahl an, unabhängig davon, ob sie erfolgreich war oder fehlgeschlagen ist.
Modrobert
1
Ok, bitte erklären Sie mir die Unterschiede: true && echo $? || echo $?/ true; echo $?und false && echo $? || echo $?/ false; echo $?- Sie werden feststellen, dass sie genau dasselbe tun: D
Javier Buzzi
Ja, das gleiche Ergebnis, aber ohne die Bedingung. Die ursprüngliche Frage lautete "Wie überprüfe ich, ob ein Befehl erfolgreich war?". Diese Frage basierte auf vorherigen Antworten. Ich denke, ein besseres Beispiel wäre:command && echo "success: $?" || echo "fail: $?"
modrobert
5

Es sollte beachtet werden, dass if...then...fiund &&/ oder der ||Typ des Ansatzes den Exit-Status behandelt, der von dem Befehl zurückgegeben wird, den wir testen möchten (0 bei Erfolg); Einige Befehle geben jedoch keinen Exit-Status ungleich Null zurück, wenn der Befehl fehlgeschlagen ist oder Eingaben nicht verarbeiten konnte. Dies bedeutet, dass die üblichen ifund &&/ ||Ansätze für diese bestimmten Befehle nicht funktionieren.

Unter Linux wird GNU beispielsweise fileimmer noch mit 0 beendet, wenn eine nicht vorhandene Datei als Argument empfangen wurde und findder angegebene Benutzer die Datei nicht finden konnte.

$ find . -name "not_existing_file"                                          
$ echo $?
0
$ file ./not_existing_file                                                  
./not_existing_file: cannot open `./not_existing_file' (No such file or directory)
$ echo $?
0

In solchen Fällen besteht eine mögliche Möglichkeit, mit der Situation umzugehen, darin, stderr/ stdinmessages zu lesen , z. B. diejenigen, die per fileBefehl zurückgegeben werden, oder die Ausgabe des Befehls wie in zu analysieren find. Zu diesem Zweck casekönnte die Anweisung verwendet werden.

$ file ./doesntexist  | while IFS= read -r output; do                                                                                                                  
> case "$output" in 
> *"No such file or directory"*) printf "%s\n" "This will show up if failed";;
> *) printf "%s\n" "This will show up if succeeded" ;;
> esac
> done
This will show up if failed

$ find . -name "doesn'texist" | if ! read IFS= out; then echo "File not found"; fi                                                                                     
File not found

(Dies ist eine Wiederholung meiner eigenen Antwort auf verwandte Fragen unter unix.stackexchange.com )

Sergiy Kolodyazhnyy
quelle
1

Wie in vielen anderen Antworten erwähnt, reicht ein einfacher Test des $?Willens aus

if [ $? -eq 0 ]; then something; fi

Wenn Sie testen möchten, ob der Befehl fehlgeschlagen ist , können Sie eine kürzere Version in bash(aber möglicherweise einen Overkill) wie folgt verwenden:

if (($?)); then something; fi

Dies funktioniert im (( ))arithmetischen Modus. Wenn also der Befehl zurückgegeben wird success, $? = 0wertet der Test ((0))die Tests als aus false, andernfalls wird er zurückgegeben true.

Um den Erfolg zu testen , können Sie Folgendes verwenden:

if ! (($?)); then something; fi

aber es ist schon nicht viel kürzer als das erste Beispiel.

afuna
quelle
1
konstruktive Kritik?
Afuna