a ERRarmadilha 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 -ea 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 EXITe 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 bashque 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 ERRarmadilha seja acionada, basta executar um comando com um status de saída diferente de zero, como falseou test.