Wie deaktiviere ich set -e für einen einzelnen Befehl?

36

Der Befehl set -e führt dazu, dass ein Bash-Skript sofort fehlschlägt, wenn ein Befehl einen Exit-Code ungleich Null zurückgibt.

  1. Gibt es eine einfache und elegante Möglichkeit, dieses Verhalten für einen einzelnen Befehl innerhalb eines Skripts zu deaktivieren?

  2. An welchen Stellen ist diese Funktionalität im Bash-Referenzhandbuch ( http://www.gnu.org/software/bash/manual/bashref.html ) dokumentiert ?

Gustave
quelle

Antworten:

29
  1. Etwas wie das:

    #!/usr/bin/env bash
    
    set -e
    echo hi
    
    # disable exitting on error temporarily
    set +e
    aoeuidhtn
    echo next line
    
    # bring it back
    set -e
    ao
    
    echo next line
    

    Lauf:

    $ ./test.sh
    hi
    ./test.sh: line 7: aoeuidhtn: command not found
    next line
    ./test.sh: line 11: ao: command not found
    
  2. Es ist in der seteingebauten Hilfe beschrieben:

    $ type set
    set is a shell builtin
    $ help set
    (...)
    Using + rather than - causes these flags to be turned off.
    

Dasselbe ist hier dokumentiert: https://www.gnu.org/software/bash/manual/bashref.html#The-Set-Builtin .

Arkadiusz Drabczyk
quelle
Vielen Dank! Ich habe eine andere Möglichkeit gefunden: #! / Bin / bash set -e # Kommentiere die nächste Zeile aus, um den Effekt von set -e zu sehen: #blubb if blubb; dann Echo "Command Blubb war erfolgreich." sonst echo "Befehl blubb fehlgeschlagen. Exitcode: $?" Fi Echo normales Skript beenden
Gustave
22

Eine Alternative zum Aufheben der Sicherheitsleistung wäre, einen Erfolg zu erzwingen, egal was passiert. Sie können so etwas tun:

cmd_to_run || true

Das gibt 0 (true) zurück, daher sollte das Set -e nicht ausgelöst werden

Ernie
quelle
3
faulty_cmd || :ist eine andere populäre Redewendung dafür. (Das :ist auch ein Befehl dazu true).
Ulidtko
3
@ulidtko - interessant. Führte mich in den Kaninchenbau dieses zu finden stackoverflow.com/questions/3224878/... die Geschichte auf wahren vs. zu bekommen:
ernie
12

Wenn Sie versuchen, den Rückgabe- / Fehlercode (Funktion oder Gabel) abzufangen, funktioniert Folgendes:

function xyz {
    return 2
}

xyz && RC=$? || RC=$?
h0tw1r3
quelle
8

Ob die Shell-Option "Sofort beenden" gilt oder ignoriert wird, hängt vom Kontext des ausgeführten Befehls ab (siehe Abschnitt "Bash-Referenzhandbuch" im Set Builtin - dank Arkadiusz Drabczyk).

Insbesondere wird die Option ignoriert, wenn ein Befehl Teil des Tests in einer if-Anweisung ist. Daher ist es möglich, einen Befehl auszuführen und mit einer if-Anweisung wie der folgenden in einem "Sofort-Exit-Kontext" auf Erfolg oder Misserfolg zu prüfen:

#!/bin/bash

set -e

# Uncomment next line to see set -e effect:
#blubb

if blubb; then
  echo "Command blubb was succesful."
else 
  echo "Command blubb failed. Exit code: $?"
fi
echo "Script exited normally."

Es ist möglich, die "then" -Anweisung wegzulassen und weniger Zeilen zu verwenden:

if blubb; then :;
else echo "Command blubb failed. Exit code: $?"; fi
Gustave
quelle
2

Ein anderer Ansatz, den ich ziemlich einfach finde (und der auch auf andere setOptionen zutrifft -e):

Verwenden Sie $-, um die Einstellungen wiederherzustellen.

Beispielsweise:

oldopt=$-
set +e
# now '-e' is definitely disabled.
# do some stuff...

# Restore things back to how they were
set -$oldopt

Obwohl -espeziell die Optionen, die andere erwähnt haben ( || trueoder "in ein if" setzen), idiomatischer sein können.

jwd
quelle
0

Tatsächlich hatte ich kürzlich eine ähnliche Frage (obwohl ich nicht gepostet habe, sondern mich darum gekümmert habe), und nach allem, was ich sehe, scheint es, als würde man nur set + e vor dem Befehl und set -e danach am elegantesten arbeiten. Hier ist ein Beispiel, in dem die Antwort des Befehls abgerufen und der Fehler nicht weggeworfen wird.

#!/bin/sh

args=""
for argcol in $*
do
    args="${args} ${argcol}"
done
fortunevar=""
fortfail=""
{
    set +e
    fortunevar=`fortune $args`
    fortfail=$?
    set -e
} &> /dev/null
if [ $fortfail == 0 ]
then
    echo ${fortunevar}
    say ${fortunevar}
else
    echo misfortune: an illegal option was detected!
    echo misfortune: usage: misfortune [-afilosw] [-m pattern][ [#%] file/directory/all]
fi

Dies erfasst die Ausgabe von 'Fortune', prüft den Ausgangsstatus und gibt das Echo wieder und sagt es aus. Ich denke, das ist es, wonach Sie gefragt haben, oder zumindest etwas Ähnliches? Wie auch immer, hoffe das hilft.

Addison Crump
quelle
Um das zu verdeutlichen, ist das, was Sie in geschweiften Klammern suchen, das, was nach / dev / null umgeleitet wird. Der Befehl wird ohne Ausgabe ausgeführt und der Fehlerstatus wird überprüft, ohne dass das Programm beendet wird.
Addison Crump
0

Ich starte gerne eine Subshell, wenn ich vorübergehend etwas ändern möchte. Der folgende Befehl zeigt, dass der erste bad_command ignoriert wird und der zweite die Ausführung abbricht.

bash -c 'set -e ;\
( set +e; bad_command ; echo still here ) ;\
echo even here ; \
bad_command ; \
echo but not here;'
noonex
quelle