我使用的是 Ubuntu 12.04.2。我正在尝试使用“trap”命令来捕获 shell 脚本中的异常或错误,但我也尝试手动触发“错误”退出。
我尝试过退出1,但它不会触发“错误”信号。
#!/bin/bash
func()
{
exit 1
}
trap "echo hi" INT TERM ERR
func
不确定如何手动触发“错误”退出信号?
答案1
该ERR
陷阱不是当 shell 本身以非零错误代码退出时运行代码,而是当该 shell 运行的任何命令不属于状况(如 inif cmd...
或cmd || ...
...)以非零退出状态退出(与导致set -e
退出 shell 的条件相同)。
如果您想在退出 shell 时以非零退出状态运行代码,您应该添加一个陷阱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
实现了等待并配合退出终端中断的处理。因此,您可能需要确保使用相同的信号来自杀,以便向您的父母报告您确实被打扰,并且如果它收到 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
。
答案2
使用 return 而不是 exit 设置函数退出时的状态(如果函数在没有返回的情况下失败,则状态为最后执行的语句的状态。)如果您在问题的示例中替换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 处理程序退出,或者删除 return 并将其作为false
func 中的最后一条语句。