ERR
pułapka nie jest do uruchomienia kodu, gdy sama powłoka kończy pracę z niezerowym kodem błędu, ale kiedy każdy prowadzony przez polecenie tego płaszcza, który nie jest częścią stanu (jak w if cmd...
, lub cmd || ...
...) wychodzi z niezerową status wyjścia (te same warunki, co powoduje set -e
wyjście z powłoki).
Jeśli chcesz uruchomić kod po wyjściu z powłoki z niezerowym statusem wyjścia, powinieneś EXIT
zamiast tego dodać pułapkę i sprawdzić $?
tam:
trap '[ "$?" -eq 0 ] || echo hi' EXIT
Zauważ jednak, że przy sygnale uwięzionym uruchamiana byłaby zarówno pułapka sygnału, jak i pułapka EXIT, więc możesz chcieć to zrobić w następujący sposób:
unset killed_by
trap 'killed_by=INT;exit' INT
trap 'killed_by=TERM;exit' TERM
trap '
ret=$?
if [ -n "$killed_by" ]; then
echo >&2 "Ouch! Killed by $killed_by"
exit 1
elif [ "$ret" -ne 0 ]; then
echo >&2 "Died with error code $ret"
fi' EXIT
Lub użyć statusu wyjścia jak w $((signum + 128))
przypadku sygnałów:
for sig in INT TERM HUP; do
trap "exit $((128 + $(kill -l "$sig")))" "$sig"
done
trap '
ret=$?
[ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"' EXIT
Zauważ jednak, że normalne wychodzenie z SIGINT lub SIGQUIT ma potencjalnie irytujące skutki uboczne, gdy proces nadrzędny jest podobny do powłoki, bash
która implementuje obsługę oczekiwania i współpracy w przypadku przerwania terminala. Możesz więc upewnić się, że zabiłeś się tym samym sygnałem, aby zgłosić rodzicowi, że rzeczywiście zostałeś przerwany i że powinien również rozważyć wyjście z siebie, jeśli otrzyma SIGINT / SIGQUIT.
unset killed_by
for sig in INT QUIT TERM HUP; do
trap "exit $((128 + $(kill -l "$sig"))); killed_by=$sig" "$sig"
done
trap '
ret=$?
[ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"
if [ -n "$killed_by" ]; then
trap - "$killed_by" # reset handler
# ulimit -c 0 # possibly disable core dumps
kill -s "$killed_by" "$$"
else
exec "$ret"
fi' EXIT
Jeśli chcesz uruchomić ERR
pułapkę, po prostu uruchom polecenie z niezerowym statusem wyjścia, takim jak false
lub test
.