我正在寻找一种方法来清理混乱时,我的顶级脚本退出。

特别是如果我想使用set -e,我希望后台进程在脚本退出时结束。


当前回答

trap 'kill $(jobs -p)'退出

我只会对Johannes的答案做一些小改动,并使用jobs -pr将kill限制为正在运行的进程,并在列表中添加更多的信号:

trap 'kill $(jobs -pr)' SIGINT SIGTERM EXIT

其他回答

更新:https://stackoverflow.com/a/53714583/302079通过添加退出状态和清除功能改进了这一点。

trap "exit" INT TERM
trap "kill 0" EXIT

为什么转换INT和TERM退出?因为两者都应该在不进入无限循环的情况下触发kill 0。

为什么在EXIT时触发kill 0 ?因为正常的脚本退出也应该触发kill 0。

为什么要杀死0?因为嵌套的子shell也需要被杀死。这会把整个过程树都画下来。

脚本的加载。运行一个killall(或操作系统上可用的任何命令)命令,该命令在脚本完成后立即执行。

如果在子shell中调用Jobs -p,则不能在所有shell中工作,除非它的输出被重定向到文件而不是管道中。(我想它最初只是用于交互使用的。)

下面这些怎么样:

trap 'while kill %% 2>/dev/null; do jobs > /dev/null; done' INT TERM EXIT [...]

Debian的dash shell需要调用“jobs”,如果缺少当前作业(“%%”),则该shell无法更新。

我把@tokland的回答与http://veithen.github.io/2014/11/16/sigterm-propagation.html的知识相结合,当我注意到如果我正在运行一个前台进程(不是后台的&),陷阱不会触发:

#!/bin/bash

# killable-shell.sh: Kills itself and all children (the whole process group) when killed.
# Adapted from http://stackoverflow.com/a/2173421 and http://veithen.github.io/2014/11/16/sigterm-propagation.html
# Note: Does not work (and cannot work) when the shell itself is killed with SIGKILL, for then the trap is not triggered.
trap "trap - SIGTERM && echo 'Caught SIGTERM, sending SIGTERM to process group' && kill -- -$$" SIGINT SIGTERM EXIT

echo $@
"$@" &
PID=$!
wait $PID
trap - SIGINT SIGTERM EXIT
wait $PID

它工作的例子:

$ bash killable-shell.sh sleep 100
sleep 100
^Z
[1]  + 31568 suspended  bash killable-shell.sh sleep 100

$ ps aux | grep "sleep"
niklas   31568  0.0  0.0  19640  1440 pts/18   T    01:30   0:00 bash killable-shell.sh sleep 100
niklas   31569  0.0  0.0  14404   616 pts/18   T    01:30   0:00 sleep 100
niklas   31605  0.0  0.0  18956   936 pts/18   S+   01:30   0:00 grep --color=auto sleep

$ bg
[1]  + 31568 continued  bash killable-shell.sh sleep 100

$ kill 31568
Caught SIGTERM, sending SIGTERM to process group
[1]  + 31568 terminated  bash killable-shell.sh sleep 100

$ ps aux | grep "sleep"
niklas   31717  0.0  0.0  18956   936 pts/18   S+   01:31   0:00 grep --color=auto sleep

这对我来说是可行的(多亏了评论的改进):

trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT

kill——-$$向整个进程组发送一个SIGTERM,因此也杀死后代。 在使用set -e时,指定信号EXIT很有用(更多细节请点击这里)。