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?

Vivek Goel
quelle

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
Igor Chubin
quelle
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.

Lars Kotthoff
quelle
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
Arslan Qadeer
quelle
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.

Lily Finley
quelle
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.."
Timo
quelle
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.

volingas
quelle
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
Payman
quelle
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

Q-Leben
quelle
0

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

var=$(echo $(exit 1)) # it shouldn't fail
Foto Blysk
quelle
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.

Konard
quelle
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
Robert.C
quelle
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 .

Almaz Gareev
quelle