在shell脚本被终止时终止运行命令

时间:2009-10-29 16:15:10

标签: bash

出于测试目的,我有这个shell脚本

#!/bin/bash
echo $$
find / >/dev/null 2>&1

从交互式终端运行,ctrl + c将终止bash和find命令。

$ ./test-k.sh
13227
<Ctrl+C>
$ ps -ef |grep find
$

在后台运行它,并且仅杀死shell将孤立在脚本中运行的命令。

$ ./test-k.sh &
[1] 13231
13231
$ kill 13231
$ ps -ef |grep find
nos 13232     1  3 17:09 pts/5    00:00:00 find /
$

我希望这个shell脚本在退出时终止所有子进程,无论它是如何被调用的。它最终将从python和java应用程序启动 - 当脚本退出时需要进行某种形式的清理 - 我应该查看的任何选项或任何重写脚本以在退出时自行清理的方法?

6 个答案:

答案 0 :(得分:15)

我会做这样的事情:

#!/bin/bash
trap : SIGTERM SIGINT

echo $$

find / >/dev/null 2>&1 &
FIND_PID=$!

wait $FIND_PID

if [[ $? -gt 128 ]]
then
    kill $FIND_PID
fi

我想有些解释是有道理的。出门,我们需要改变一些默认的信号处理。 :是一个无操作命令,因为传递一个空字符串会导致shell忽略信号而不是对它做一些事情(与我们想做的事情相反)。

然后,find命令在后台运行(从脚本的角度来看),我们调用wait内置函数来完成它。由于我们向上面的trap发出了实际命令,因此当处理信号时,wait将以大于128的状态退出。如果完成的进程wait完成,{{1} }将返回该进程的退出状态。

最后,如果wait返回该错误状态,我们希望wait子进程。幸运的是我们保存了它的PID。此方法的优点是您可以记录一些错误消息或以其他方式识别信号导致脚本退出。

正如其他人所提到的,如果您不关心在退出后留下任何信息,那么将kill作为您kill -- -$$的参数是另一种选择。

要让trap以您想要的方式工作,您需要将其与trap配对 - wait手册页说“如果bash正在等待命令完成并接收已设置bash的信号,在命令完成之前不会执行trap。“ trap是绕过这个打嗝的方法。

如果需要,您可以将其扩展到更多子进程。我并没有详尽地测试这个,但它似乎在这里工作。

wait

答案 1 :(得分:8)

正在为这个问题寻找一个优雅的解决方案,并在其他地方找到了以下解决方案。

trap 'kill -HUP 0' EXIT

我自己的手册没有说明0的含义,但是从挖掘中看,它似乎意味着当前的流程组。由于脚本是自己的进程组,因此最终会向所有脚本的子节点,前景和后台发送SIGHUP。

答案 2 :(得分:6)

向小组发送信号。 因此,而不是kill 13231做:

kill -- -13231

如果你是从python开始,那么看看: http://www.pixelbeat.org/libs/subProcess.py 它展示了如何在启动时模仿shell 并杀死一个团体

答案 3 :(得分:1)

只需在脚本中添加这样的行:

trap "kill $$" SIGINT

您可能需要在设置中将“SIGINT”更改为“INT”,但这会在您按Ctrl-C时基本上终止您的进程和所有子进程。

答案 4 :(得分:1)

@Patrick的回答几乎完成了这个诀窍,但是如果当前 shell的进程在同一个组中(它也杀死了父进程)它就不起作用)。

我发现这更好:

trap 'pkill -P $$' EXIT

有关详细信息,请参阅here

答案 5 :(得分:0)

你需要做的是捕获kill信号,杀死find命令并退出。