ERR
пастка не для запуску коду , коли сама оболонка виходить з ненульовим кодом помилки, але коли будь-яка команда запуску цієї оболонки , яка не є частиною стану (наприклад , в if cmd...
, або cmd || ...
...) виходить з ненульовим статус виходу (ті ж умови, що і причину set -e
виходу з оболонки).
Якщо ви хочете запустити код після виходу з оболонки з ненульовим статусом виходу, слід EXIT
замість цього додати пастку і перевірити $?
там:
trap '[ "$?" -eq 0 ] || echo hi' EXIT
Однак зауважте, що при захопленому сигналі буде запускатися і сигнальна пастка, і EXIT, і ви можете зробити це так:
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
Або використовувати статус виходу, як $((signum + 128))
за сигналами:
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
Зауважте, однак, що звичайний вихід при SIGINT або SIGQUIT має потенційні роздратовані побічні ефекти, коли ваш батьківський процес є оболонкою, bash
яка реалізує обробку виходу очікування та спільного переривання терміналу. Таким чином, ви можете переконатися, що ви вбили себе тим самим сигналом, щоб повідомити батькові, що вас дійсно перервали, і щоб він міг також вийти з себе, якщо він отримав Знак / Знак.
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
Якщо ви хочете, щоб ERR
пастка спрацьовувала, просто запустіть команду зі статусом виходу з нуля, наприклад, false
або test
.