2009-10-29 87 views
13

出于测试目的,我有这个shell脚本终止正在运行的命令时,shell脚本被杀害

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

从交互终端,CTRL + C运行,这将终止庆典,并find命令。

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

运行在后台,杀壳只会孤立在脚本执行上面的命令。

$ ./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应用程序开始 - 当脚本退出时需要某种形式的清理 - 我应该查看的任何选项或以任何方式重写脚本以在退出时自行清理?

回答

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,则wait将返回该进程的退出状态。

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

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

对于trap工作,你想要的方式,你需要与wait配对起来 - 在bash手册页说:“如果bash正在等待命令完成并收到其中trap已设置的信号,直到命令完成,trap才会被执行。“ wait就是绕过这个呃逆。

如果您愿意,也可以将其扩展到更多子进程。我没有真正详尽地测试这一个,但它似乎在这里工作。

$ ./test-k.sh & 
[1] 12810 
12810 
$ kill 12810 
$ ps -ef | grep find 
$ 
+1

传统的无操作命令是“':'”。 – ephemient 2009-10-29 17:21:27

+0

很热。现在改变它。 – 2009-10-29 17:30:25

+0

如果我在后台启动进程,那么它不会被杀死。如果我不在后台启动,生成的子进程确实会被杀死 – 2011-06-14 20:32:53

0

你需要做的事情是陷阱kill信号,杀死查找命令并退出。

+3

'kill'默认发送'SIGTERM'。 'SIGKILL'不可捕捉。 – 2009-10-29 16:34:55

1

就这样添加一行脚本:

trap "kill $$" SIGINT 

您可能需要更改“SIGINT”到你的设置“INT”,但这基本上会杀了你的进程和所有子进程,当你按Ctrl-C。

+2

而不是'kill $$',你可能应该将TERM发送给find命令的pid! – 2009-10-29 16:41:49

+1

'$!'也许,虽然你可能想要比这更好的控制。 – ephemient 2009-10-29 17:23:30

6

发送信号给组。 所以不是kill 13231做:

kill -- -13231 

如果你从蟒蛇开始,然后看看: http://www.pixelbeat.org/libs/subProcess.py 展示了如何模仿壳开始 和杀害一组

+0

此脚本中的每个命令是否属于该进程组? – nos 2009-10-29 17:33:01

+0

如果从shell启动是的,否则您需要像在subProcess.py – pixelbeat 2009-10-30 10:49:15

+0

中那样开始。您并不总是能够控制脚本将被终止的方式 – ndemou 2015-10-14 16:14:58

7

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

trap 'kill -HUP 0' EXIT 

我自己的手册页说什么什么0手段,但是从周围挖掘,这似乎意味着当前进程组。由于脚本得到了它自己的进程组,所以最终将SIGHUP发送给所有脚本的子进程,前台和后台。

+0

这似乎很好地工作(尝试通过ctrl-C关闭终端来杀死脚本),但我害怕隐藏的缺点。任何bash大师愿意分享他的意见? – ndemou 2015-10-14 16:13:33

+0

http://stackoverflow.com/a/22644006/301717提出了类似的答案,但似乎更强大 – Jezz 2016-08-23 14:48:05

1

@帕特里克的回答几乎是没有的伎俩,但如果你的当前壳的过程是在同一个组(它杀死父太)这是行不通的。

我觉得这是更好的:

trap 'pkill -P $$' EXIT

更多信息,请参见here

相关问题