Answers:
ERR
当shell自身以非零错误代码退出时,陷阱不运行代码,而是当该shell运行的任何不属于条件的命令(如in 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
但是请注意,当您的父进程是像bash
这样的shell时,通常会在SIGINT或SIGQUIT上退出,这可能会带来令人讨厌的副作用,该shell 实现了终端中断的等待和协作退出处理。因此,您可能需要确保使用相同的信号杀死自己,以便向父母报告您确实遭到了打扰,并且如果收到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
在问题的例子,它将作为工作我认为您打算这样做:陷阱将在ERR伪信号上触发,并显示“ hi”。出于其他考虑,请尝试以下操作:
#!/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陷阱,不取消ERR处理程序中的EXIT陷阱,不从ERR处理程序中退出或删除返回值并将其false
作为func中的最后一条语句。