У меня была удача с коммерческой программой SpinRite на уровне 2 с палками usb. Если Вы недовольны результатами, я полагаю, что существует гарантия возврата денег.
ERR
прерывание не должно выполнять код, когда сама оболочка выходит с ненулевым кодом ошибки, но когда любая команда, выполненная той оболочкой, которая не является частью условия (как в if cmd...
, или cmd || ...
...) выходит с ненулевым статусом выхода (те же условия, как какой причины set -e
выходить из оболочки).
Если Вы хотите выполнить код выхода оболочки с ненулевым статусом выхода, необходимо включить прерывание EXIT
вместо этого и проверка $?
там:
trap '[ "$?" -eq 0 ] || echo hi' 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
это реализует ожидание и совместную обработку выхода терминального прерывания. Так, можно хотеть удостовериться, что уничтожили себя с тем же сигналом вместо этого, чтобы сообщить Вашему родителю, что Вы были действительно прерваны, и что он должен рассмотреть выход из себя также, если бы он получил 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
Если Вы хотите ERR
захватите, чтобы стрелять, просто выполнить команду с ненулевым статусом выхода как false
или test
.
Используйте return, а не exit, чтобы установить статус при выходе из функции (если функция не выполняется без возврата, статус соответствует состоянию последней выполненной инструкции). Если вы подставляете return
для exit
в примере с вопросом он будет работать так, как я думаю, вы задумали: ловушка срабатывает по псевдосигналу ERR, и будет напечатано «привет». Для дополнительных соображений попробуйте следующее:
#!/bin/bash
func()
{
echo 'in func'
return 99
echo 'still in func'
}
trap 'echo "done"' EXIT
trap 'status=$?; echo "error status is $status"; trap - EXIT; exit $status' ERR
func
echo 'returned from func'
Вы можете попробовать различные модификации, такие как возврат 0, комментирование ловушки ERR, отказ от отмены ловушки EXIT в обработчике ERR, отказ от выхода из обработчика ERR или удаление возврата и установка false
как последний оператор в func.