Kann jemand das Bash / Set-e-Verhalten im folgenden Code-Snippet erklären?
#!/bin/bash
# Comment if you want to test the trap only
set -e -o pipefail -u -E
# Comment if you want to test the set -e only
trap "echo ERROR CAUGHT; exit 12" ERR
function reproduce() {
# Trigger arithmetic error on purpose
a=$((1109962735 - hello=12272 + 1))
}
reproduce
# The script is expected to trigger the trap and/or activate the set -e. In both cases it should stop and exit here on error.
status_code=$?
echo "STATUS ${status_code}"
if [[ "${status_code}" != "0" ]];then
echo "FIXME: why was status code not caught by set -e ?"
echo "Executing false to prove set -e is still active"
false
# If the following is not executed then it proves -e is still active
echo "set -e not active !!!!!"
exit 2
fi
Folgendes wird bei der Ausführung erhalten:
$ bash reproduce.sh
reproduce.sh: line 8: 1109962735 - hello=12272 + 1: attempted assignment to non-variable (error token is "=12272 + 1")
STATUS 1
FIXME: why was status code it not caught by set -e ?
Executing false to prove set -e is still active
ERROR CAUGHT
Überprüfen des Exit-Codes
$ echo $?
1
Bash-Version
bash --version
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
Auch reproduziert mit
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
Zusätzliche Hinweise zu Kommentaren (trotzdem danke an alle Vorschläge):
- Das Kommentieren der Falle ändert nichts an dem beobachteten seltsamen Verhalten
- Wenn Sie set -e entfernen, um nur die Falle zu behalten, wird die Falle ebenfalls ausgelöst
set -e
mittrap
.trap
wird bei einem Fehler aufgerufen und "echo ERROR CAUGHT" wird aufgerufen. Ich habe den Eindruck, dasstrap
Vorrang hat alsset -e
. Laut Bash-FAQ, die ich fürset -e
entmutigt halte , überprüfen Sie bitte mywiki.wooledge.org/BashFAQ/105 .trap
stattdessen einfach den Mechanismus verwenden, ztrap "exit 2" ERR
. Auch für mich druckt Ihr Skript nur "STATUS 0". Die ERR-Falle wird anscheinend nicht von Shell-Funktionen geerbt. Hilft dies :set -o errtrace
? Ansonsten siehe meinen Link oben, warum du das überhaupt vermeiden solltestset -e
.Antworten:
Vereinfachen wir es; Die Mindestmenge an Code, die zum Reproduzieren des Problems erforderlich ist, ist
Laut Standard sollte dies niemals gedruckt
survived
werden. Eine nicht interaktiv laufende POSIX-Shell soll bei einem Erweiterungsfehler sofort beendet werden . Aber anscheinend glaubt Bash das nicht. Obwohl dieser Unterschied nicht explizit in der man - Seite dokumentiert, in Beschreibung des POSIX - Modus es sagtWir können sagen, dass dies bedeutet, dass eine nicht interaktive Bash-Sitzung im Standardbetriebsmodus bei einem solchen Fehler nicht beendet wird, aber wie Sie erkannt haben, löst sie weder einen Errexit-Mechanismus noch eine ERR-Falle aus. Stattdessen weist es einem Weitergehen einen Wert ungleich Null zu
$?
.Um dies zu überwinden und das erwartete Verhalten zu erhalten, sollten Sie
reproduce
Folgendes definierenAuf diese Weise tritt der Erweiterungsfehler in einer Unterschale auf und bewirkt, dass sie mit einem Status ungleich Null beendet wird, sodass Errexit und Trap ihn abfangen können.
Auf Anforderung von dash-o finden Sie hier eine Version, die
a
für die aktuelle Ausführungsumgebung festgelegt wird, wenn der Ausdruck gültig istquelle
An der Oberfläche sieht es so aus, als würde Bash die Falle bei verschiedenen SYNTAX-Fehlern nicht auslösen. Nur wenn ein Befehl (extern, integriert) ausgeführt wird (und nicht Null zurückgibt), wird der ERR-Trap ausgelöst.
Von der Manpage:
Die ERR-Falle gilt nur für PIPELINE . Wenn bash einen Syntaxfehler feststellt, wird dieser vor dem Ausführen der Pipeline abgebrochen, daher KEIN Trap. Obwohl die Dokumentation für '-e' dieselbe Bedingung (
if a pipeline ... exit with non-zero status
) angibt , ist das beobachtete Verhalten unterschiedlich.Wenn Sie andere Erweiterungen ausprobieren - z. B. Befehlserweiterung - wird Trap ausgelöst, da die Pipeline ausgeführt wird:
Wenn Sie versuchen, verschiedene Syntaxfehler in der arithmetischen Erweiterung zu versuchen, Trap nicht ausgelöst - es gab keine Pipeline.
Auch andere Bash-Syntaxfehler lösen den Trap nicht aus:
()
,[[ ]]
.Ich konnte keine Lösung finden, die keine umfangreichen Änderungen am Quellenskript erfordert. Kann eine Bash / Feature-Anfrage beim Bash-Team eingereicht werden?
quelle
( a=$((1109962735 - hello=12272 + 1)) )
oder Ausführen( reproduce )
der Falle.a
wird er leider nicht festgelegt.