Fehler beim Bash-Ignorieren für einen bestimmten Befehl


444

Ich verwende folgende Optionen

set -o pipefail
set -e

Im Bash-Skript, um die Ausführung bei einem Fehler zu stoppen. Ich habe ~ 100 Zeilen Skript ausgeführt und möchte nicht den Rückkehrcode jeder Zeile im Skript überprüfen.

Aber für einen bestimmten Befehl möchte ich den Fehler ignorieren. Wie kann ich das machen?

Antworten:


757

Die Lösung:

particular_script || true

Beispiel:

$ cat /tmp/1.sh
particular_script()
{
    false
}

set -e

echo one
particular_script || true
echo two
particular_script
echo three

$ bash /tmp/1.sh
one
two

three wird nie gedruckt.

Außerdem möchte ich hinzufügen, dass pipefailes für die Shell ausreicht, zu denken, dass die gesamte Pipe einen Exit-Code ungleich Null hat, wenn einer der Befehle in der Pipe einen Exit-Code ungleich Null hat (bei pipefailausgeschaltet muss es der letzte sein). .

$ set -o pipefail
$ false | true ; echo $?
1
$ set +o pipefail
$ false | true ; echo $?
0

15
+1. Wie im Bash-Referenzhandbuch erläutert , wird "Die Shell wird nicht beendet", wenn das -eAttribut festgelegt wird, "wenn der fehlgeschlagene Befehl Teil der Befehlsliste ist, die unmittelbar auf ein Schlüsselwort whileoder folgt until, Teil des Tests in einer ifAnweisung, Teil eines ausgeführten Befehls in einer &&oder ||Liste mit Ausnahme des Befehls nach dem letzten &&oder einem ||beliebigen Befehl in einer Pipeline außer dem letzten oder wenn der Rückgabestatus des Befehls mit invertiert wird !. "
Ruakh

@IgorChubin Ich weiß nicht warum, aber das funktioniert nicht output = (ldd $2/bin/* || true) | grep "not found" | wc -lscript wird nach dieser Zeile beendet, wenn ldd return fehlschlägt
Vivek Goel

1
(ldd $2/bin/* || true) | grep "not found" | wc -l || true
Igor Chubin

1
wegen set -o pipefail. Wenn grepnichts gefunden wird, wird ein Exit-Code ungleich Null zurückgegeben, und die Shell kann davon ausgehen, dass die gesamte Pipe einen Exit-Code ungleich Null hat.
Igor Chubin

3
Wenn Sie die Option haben möchten, den Rückgabewert beizubehalten (ohne ihn zu beenden), versuchen Sie es mit mycommand && true. Auf diese Weise können Sie den Rückkehrcode in den folgenden Schritten überprüfen und programmgesteuert verarbeiten.
Ed Ost

178

Fügen || trueSie einfach nach dem Befehl hinzu, wo Sie den Fehler ignorieren möchten.


11
Ich denke, es ist wichtig, dies hinzuzufügen: Diese Methode lässt den Antwortcode und die Fehlermeldung bestehen, während das "!" Die unten beschriebene Methode ändert den Antwortcode und generiert daher keinen Fehler. Dies ist wichtig, wenn Sie set -eversuchen, eine Fehlermeldung zu erfassen: z. B.set -e; TEST=$(foo 2>&1 || true); echo $TEST
Spanky

87

Halten Sie nicht an und speichern Sie auch den Exit-Status

Nur für den Fall, dass Ihr Skript nicht angehalten werden soll, wenn ein bestimmter Befehl fehlschlägt, und Sie auch den Fehlercode des fehlgeschlagenen Befehls speichern möchten:

set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE

2
Dies ist genau das, was ich brauchte
Sarink

funktioniert aus irgendeinem Grund nicht für mich ...
na ja

EXIT_CODE wird nicht auf Null gesetzt, wenn der Befehl 0 zurückgibt. Es werden jedoch Exit-Codes ungleich Null erfasst. Irgendeine Idee warum?
Ankita13

@ Ankita13 Denn wenn es Null war, war das erste commanderfolgreich und es muss ausgeführt werden, was danach ist ||. Lesen Sie es wie commandfolgt : Wenn dies fehlschlägt, tun Sie es EXIT_CODE=$?. Sie könnten wahrscheinlich einfach command || echo "$?""trap" für ein ausführlicheres Debugging verwenden. Siehe dies -> stackoverflow.com/a/6110446/10737630
tinnick

63

Genauer gesagt:

! particular_script

Aus der POSIX-Spezifikation bezüglich set -e(Schwerpunkt Mine):

Wenn diese Option aktiviert ist, wenn ein einfacher Befehl aus einem der unter Konsequenzen von Shell-Fehlern aufgeführten Gründe fehlschlägt oder einen Exit-Statuswert> 0 zurückgibt und nach einer Weile nicht mehr Teil der zusammengesetzten Liste ist, bis oder wenn das Schlüsselwort und ist kein Teil einer UND- oder ODER-Liste und keine Pipeline, der das! reserviertes Wort , dann wird die Shell sofort verlassen.


16
Dies invertiert nur den Exit-Code eines Befehls, sodass ein erfolgreich abgeschlossener Befehl 1 anstelle von 0 zurückgibt und das Skript mit fehlschlägt -e.
Marboni

17
Mein Verständnis ist, dass der !Wille verhindert, dass die Shell auf jeden Fall austritt. Dieses Skript zeigt die Meldung an, Still alive!wenn ich es ausführe, und zeigt an, dass das Skript vollständig ausgeführt wurde. Sehen Sie ein anderes Verhalten?
Lily Finley

7
Sie haben Recht, es kehrt den Exit-Status um, stürzt aber nicht ab, wenn der Befehl mit 0 oder 1 endet. Ich war unaufmerksam. Wie auch immer, danke, dass Sie die Dokumentation zitiert haben. Ich habe meinen Ausdruck in ifKlausel gesetzt und das Problem gelöst.
Marboni

42

Anstatt "true zurückzugeben", können Sie auch das Dienstprogramm "noop" oder null (wie in den POSIX-Spezifikationen angegeben ) verwenden :und einfach "nichts tun". Sie werden ein paar Briefe speichern. :) :)

#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."

3
obwohl ||: ist nicht so klar wie || wahr (was nicht erfahrene Benutzer verwirren kann), ich mag es Prägnanz
David

Diese Variante gibt keinen Text zurück, der in CI wichtig sein kann.
Kivagant

5

Wenn Sie verhindern möchten, dass Ihr Skript fehlschlägt, und den Rückkehrcode erfassen:

command () {
    return 1  # or 0 for success
}

set -e

command && returncode=$? || returncode=$?
echo $returncode

returncode wird unabhängig davon gesammelt, ob der Befehl erfolgreich ist oder fehlschlägt.


2

Ich habe das folgende Snippet bei der Arbeit mit CLI-Tools verwendet und möchte wissen, ob eine Ressource vorhanden ist oder nicht, aber die Ausgabe ist mir egal.

if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
    echo "none exist actually exist!"
fi

1
Dies scheint ein wirklich if [ -r not_exist ]
umständlicher

1

Diese Lösung gefällt mir irgendwie:

: `particular_script`

Der Befehl / das Skript zwischen den Back-Ticks wird ausgeführt und seine Ausgabe wird dem Befehl ":" zugeführt (was "true" entspricht).

$ false
$ echo $?
1
$ : `false`
$ echo $?
0

edit: Hässlicher Tippfehler behoben


0

während || trueist bevorzugt, aber Sie können auch tun

var=$(echo $(exit 1)) # it shouldn't fail

0

Von hier aus haben keine Lösungen für mich funktioniert, daher habe ich eine andere gefunden:

set +e
find "./csharp/Platform.$REPOSITORY_NAME/obj" -type f -iname "*.cs" -delete
find "./csharp/Platform.$REPOSITORY_NAME.Tests/obj" -type f -iname "*.cs" -delete
set -e

Dies ist nützlich für CI & CD. Auf diese Weise werden die Fehlermeldungen gedruckt, aber das gesamte Skript wird weiterhin ausgeführt.


0
output=$(*command* 2>&1) && exit_status=$? || exit_status=$?
echo $output
echo $exit_status

Beispiel für die Verwendung zum Erstellen einer Protokolldatei

log_event(){
timestamp=$(date '+%D %T') #mm/dd/yy HH:MM:SS
echo -e "($timestamp) $event" >> "$log_file"
}

output=$(*command* 2>&1) && exit_status=$? || exit_status=$?

if [ "$exit_status" = 0 ]
    then
        event="$output"
        log_event
    else
        event="ERROR $output"
        log_event
fi

0

Vielen Dank für die einfache Lösung hier von oben:

<particular_script/command> || true

Die folgende Konstruktion kann für zusätzliche Aktionen / Fehlerbehebung bei Skriptschritten und zusätzliche Optionen zur Flusssteuerung verwendet werden:

if <particular_script/command>
then
   echo "<particular_script/command> is fine!"
else
   echo "<particular_script/command> failed!"
   #exit 1
fi

Wir können die weiteren Maßnahmen und exit 1bei Bedarf bremsen .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.