如何杀死shell的所有子进程?
Posted
技术标签:
【中文标题】如何杀死shell的所有子进程?【英文标题】:How to kill all subprocesses of shell? 【发布时间】:2011-02-06 18:51:03 【问题描述】:我正在编写一个 bash 脚本,它做了几件事。
一开始它会启动几个监控脚本,每个脚本都运行一些其他工具。
在我的主脚本结束时,我想杀死所有从我的 shell 中生成的东西。
所以,它可能看起来像这样:
#!/bin/bash
some_monitor1.sh &
some_monitor2.sh &
some_monitor3.sh &
do_some_work
...
kill_subprocesses
问题是这些监视器中的大多数都会产生自己的子进程,所以这样做(例如):killall some_monitor1.sh
并不总是有帮助。
有没有其他办法处理这种情况?
【问题讨论】:
一个很棒的帖子:***.com/questions/392022/… 【参考方案1】:pkill -P $$
适合(只是杀死它自己的后代)
编辑:我投了反对票,不知道为什么。无论如何,这里是-P的帮助
-P, --parent ppid,...
Only match processes whose parent process ID is listed.
而$$
是process id of the script itself
【讨论】:
不杀死通过直接子进程的后代。 @Chexpir:它不是 bash 的一部分。但是,如果您的系统没有它,那么您就处于 deep5h1t 中。它是 Ubuntu 下procps
软件包的一部分,该软件包包含其他核心实用程序,例如 free
、kill
和 ps
。
赞成。然而在我的情况下,这些过程非常顽固,所以我不得不用信号 9 杀死它们,就像pkill -P $$ --signal 9
@pihentagy 没有竞争条件吗? pkill 本身是当前 shell 的子级。因此,“pkill -P $$”会在所有其他进程被杀死之前杀死“pkill”进程吗?
不,这里没有竞争条件。 pkill 是 pgrep 的符号链接,在 pgrep.c 的第 441 行中,您可以看到 pkill 在检查要杀死的进程时会跳过自身。因此,在杀死所有其他孩子之后,pkill 命令将定期终止。【参考方案2】:
启动每个子进程后,可以通过
ID=$!
然后您可以使用存储的 PID 来查找并杀死所有孙子等进程,如 here 或 here 所述。
【讨论】:
只是补充一点,如果监视器的子进程可以产生子子进程等,您需要递归地使用链接中描述的技术。 @David 提到的第二页包含一个解决方案。 是的,但是当我写评论时,第二个链接还没有出现。 第一个链接失效了,彼得。【参考方案3】:如果您使用带有kill
的负PID,它将杀死一个进程组。示例:
kill -- -1234
【讨论】:
【参考方案4】:扩展 pihentagy 的答案以递归地杀死所有后代(不仅仅是孩子):
kill_descendant_processes()
local pid="$1"
local and_self="$2:-false"
if children="$(pgrep -P "$pid")"; then
for child in $children; do
kill_descendant_processes "$child" true
done
fi
if [[ "$and_self" == true ]]; then
kill -9 "$pid"
fi
现在
kill_descendant_processes $$
将杀死当前脚本/shell的后代。
(在 Mac OS 10.9.5 上测试。仅依赖 pgrep 和 kill)
【讨论】:
好的,但请不要使用kill -9
“默认”,更改进程退出! serverfault.com/a/415744/55046
最佳答案。谢谢。【参考方案5】:
kill $(jobs -p)
Rhys Ulerich的建议:
注意竞争条件,使用 [下面的代码] 可以完成 Jürgen 的建议,而不会在不存在作业时导致错误
[[ -z "$(jobs -p)" ]] || kill $(jobs -p)
【讨论】:
警告竞争条件,使用'test -z "`jobs -p`" || kill `jobs -p`' 完成了 Jürgen 的建议,而不会在没有作业存在时引发错误【参考方案6】:带有选项“-P”的 pkill 应该会有所帮助:
pkill -P $(pgrep some_monitor1.sh)
来自手册页:
-P ppid,...
Only match processes whose parent process ID is listed.
linuxquests.org上有一些讨论,请查看:
http://www.linuxquestions.org/questions/programming-9/use-only-one-kill-to-kill-father-and-child-processes-665753/
【讨论】:
如果你已经启动了 2 次呢?一个会杀死其他子进程! @pihentagy 系统上的每个唯一的、正在运行的进程(相对于工具)都有一个唯一的 PID。如果您打开两个终端然后一个进程监视器,监视器将显示两个不同的“sh”进程,每个进程都有自己的 PID。但是,您是对的,您可以通过名称获取进程来破坏事物,这些进程不必是(并且通常不是)唯一的。【参考方案7】:我喜欢以下简单的方法:使用具有某些名称/值的环境变量启动子进程,然后使用它来终止子进程。最方便的是使用正在运行的 bash 脚本的进程 ID,即 $$。当子进程在继承环境时启动另一个子进程时,这也适用。
所以像这样启动子流程:
MY_SCRIPT_TOKEN=$$ some_monitor1.sh &
MY_SCRIPT_TOKEN=$$ some_monitor2.sh &
然后像这样杀死他们:
ps -Eef | grep "MY_SCRIPT_TOKEN=$$" | awk 'print $2' | xargs kill
【讨论】:
以上是关于如何杀死shell的所有子进程?的主要内容,如果未能解决你的问题,请参考以下文章
无法弄清楚如何在 Python 3.5 中杀死子进程 [重复]
如何在 python 中杀死使用 subprocess.call 调用的子进程? [复制]