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

nos*_*nos 16 bash

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

#!/bin/bash
echo $$
find / >/dev/null 2>&1
Run Code Online (Sandbox Code Playgroud)

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

$ ./test-k.sh
13227
<Ctrl+C>
$ ps -ef |grep find
$
Run Code Online (Sandbox Code Playgroud)

在后台运行它,并且仅杀死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 /
$
Run Code Online (Sandbox Code Playgroud)

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

Car*_*rum 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

正如其他人所提到的那样,如果你不关心在退出后留下任何信息,那么kill -- -$$作为你的论据trap是另一种选择.

为了trap按照你想要的方式工作,你需要将它配对wait- bash手册页说"如果 bash正在等待命令完成并接收trap已经设置了a的信号,那么trap在命令完成之前不会执行". wait是围绕这个打嗝的方式.

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

$ ./test-k.sh &
[1] 12810
12810
$ kill 12810
$ ps -ef | grep find
$
Run Code Online (Sandbox Code Playgroud)


Pat*_*ick 8

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

trap 'kill -HUP 0' EXIT
Run Code Online (Sandbox Code Playgroud)

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


pix*_*eat 6

向该组发送信号.所以不kill 13231要这样做:

kill -- -13231
Run Code Online (Sandbox Code Playgroud)

如果您从python开始,请查看:http: //www.pixelbeat.org/libs/subProcess.py ,其中显示了如何在启动和终止组时模仿shell