a ERR
armadilha não é para executar código quando o próprio shell sai com um código de erro diferente de zero, mas quando qualquer comando executado por esse shell que não faz parte de uma condição (como em if cmd...
, ou cmd || ...
...) sai com um valor diferente de zero status de saída (as mesmas condições que causam set -e
a saída do shell).
Se você deseja executar o código na saída do shell com status de saída diferente de zero, adicione uma interceptação EXIT
e verifique $?
lá:
trap '[ "$?" -eq 0 ] || echo hi' EXIT
Observe, porém, que, em um sinal interceptado, a interceptação de sinal e a EXIT seriam executadas, portanto, você pode fazer o seguinte:
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
Ou para usar o status de saída como $((signum + 128))
nos sinais:
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
Observe, porém, que sair normalmente de SIGINT ou SIGQUIT tem efeitos colaterais irritantes em potencial quando o processo pai é um shell como o bash
que implementa o tratamento de espera e saída cooperativa da interrupção do terminal. Portanto, você pode querer se matar com o mesmo sinal, a fim de relatar aos seus pais que você foi realmente interrompido e que ele deve considerar sair também se receber um 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
Se você deseja que a ERR
armadilha seja acionada, basta executar um comando com um status de saída diferente de zero, como false
ou test
.