Joh*_*itb 166
要清理一些乱七八糟的东西,trap可以使用.它可以提供特定信号到达时执行的内容列表:
trap "echo hello" SIGINT
Run Code Online (Sandbox Code Playgroud)
但是如果shell退出,也可以用来执行某些操作:
trap "killall background" EXIT
Run Code Online (Sandbox Code Playgroud)
它是内置的,因此help trap会为您提供信息(与bash一起使用).如果你只想杀死后台工作,你可以这样做
trap 'kill $(jobs -p)' EXIT
Run Code Online (Sandbox Code Playgroud)
注意使用单一',以防止外壳$()立即替换.
tok*_*and 154
这对我有用(感谢评论者的改进):
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
Run Code Online (Sandbox Code Playgroud)
kor*_*man 104
更新:https://stackoverflow.com/a/53714583/302079通过添加退出状态和清除功能来改进此功能.
trap "exit" INT TERM
trap "kill 0" EXIT
Run Code Online (Sandbox Code Playgroud)
为什么要转换INT并TERM退出?因为两者都应该触发kill 0而不进入无限循环.
为什么引发kill 0的EXIT?因为正常的脚本退出也应该触发kill 0.
为什么kill 0?因为嵌套的子壳也需要被杀死.这将取消整个流程树.
小智 21
陷阱'kill $(jobs -p)'退出
我只会对Johannes的回答进行微小的更改,并使用jobs -pr将kill限制为正在运行的进程,并向列表中添加更多信号:
trap 'kill $(jobs -pr)' SIGINT SIGTERM EXIT
Run Code Online (Sandbox Code Playgroud)
sko*_*zin 14
trap 'kill 0' SIGINT SIGTERM EXIT在@ tokland的答案中描述的解决方案非常好,但是最新的Bash 在使用时崩溃并出现了分段错误.这是因为Bash从v.4.3开始,允许陷阱递归,在这种情况下变为无限:
SIGINT或SIGTERM或EXIT;kill 0,发送SIGTERM到组中的所有进程,包括shell本身;这可以通过手动取消注册陷阱来解决:
trap 'trap - SIGTERM && kill 0' SIGINT SIGTERM EXIT
Run Code Online (Sandbox Code Playgroud)
更奇特的方式,允许打印收到的信号,并避免"终止:"消息:
#!/usr/bin/env bash
trap_with_arg() { # from https://stackoverflow.com/a/2183063/804678
local func="$1"; shift
for sig in "$@"; do
trap "$func $sig" "$sig"
done
}
stop() {
trap - SIGINT EXIT
printf '\n%s\n' "recieved $1, killing children"
kill -s SIGINT 0
}
trap_with_arg 'stop' EXIT SIGINT SIGTERM SIGHUP
{ i=0; while (( ++i )); do sleep 0.5 && echo "a: $i"; done } &
{ i=0; while (( ++i )); do sleep 0.6 && echo "b: $i"; done } &
while true; do read; done
Run Code Online (Sandbox Code Playgroud)
UPD:添加了最小的例子; 改进了stop功能以避免去除不必要的信号并隐藏输出中的"已终止:"消息.感谢Trevor Boyd Smith的建议!
为了安全起见,我发现最好定义一个清理函数并从陷阱中调用它:
cleanup() {
local pids=$(jobs -pr)
[ -n "$pids" ] && kill $pids
}
trap "cleanup" INT QUIT TERM EXIT [...]
Run Code Online (Sandbox Code Playgroud)
或者完全避免这个功能:
trap '[ -n "$(jobs -pr)" ] && kill $(jobs -pr)' INT QUIT TERM EXIT [...]
Run Code Online (Sandbox Code Playgroud)
为什么?因为只需使用trap 'kill $(jobs -pr)' [...]一个假定存在将是当陷阱条件获得信号,运行后台作业.当没有工作时,人们会看到以下(或类似)消息:
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
Run Code Online (Sandbox Code Playgroud)
因为jobs -pr是空的 - 我结束了'陷阱'(双关语).
小智 5
function cleanup_func {
sleep 0.5
echo cleanup
}
trap "exit \$exit_code" INT TERM
trap "exit_code=\$?; cleanup_func; kill 0" EXIT
# exit 1
# exit 0
Run Code Online (Sandbox Code Playgroud)
类似于/sf/answers/1585080451/,但添加了退出代码