如何杀死shell的所有子进程?

5uzkadbs  于 2023-02-24  发布在  Shell
关注(0)|答案(9)|浏览(208)

我正在编写一个bash脚本,它可以做几件事。
开始时,它启动几个监视器脚本,每个脚本运行一些其他工具。
在主脚本的末尾,我想杀死所有从shell派生的东西。
因此,它可能看起来像这样:

#!/bin/bash

some_monitor1.sh &
some_monitor2.sh &
some_monitor3.sh &

do_some_work
...

kill_subprocesses

问题是,大多数监视器都会产生自己的子进程,因此(例如):killall some_monitor1.sh并不总是有帮助。
有没有其他办法处理这种情况?

yyyllmsg

yyyllmsg1#

pkill -P $$

会适合(只会杀死它自己的后代)
编辑:我被否决了,不知道为什么.不管怎样,这里有-P的帮助

-P, --parent ppid,...
          Only match processes whose parent process ID is listed.

$$是脚本本身的进程ID

2w3kk1z5

2w3kk1z52#

启动每个子进程后,可以使用以下命令获取其id

ID=$!

然后,您可以使用存储的PID查找并终止所有孙进程等,如herehere所述。

qyyhg6bp

qyyhg6bp3#

如果您在kill中使用负PID,则会终止进程组。例如:
kill -- -1234

brccelvz

brccelvz4#

扩展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)

jobtbby3

jobtbby35#

kill $(jobs -p)

Rhys Ulerich的建议:
警告:在争用条件下,使用[下面的代码]可以实现Jürgen建议的功能,并且在不存在作业时不会导致错误

[[ -z "$(jobs -p)" ]] || kill $(jobs -p)
yizd12fk

yizd12fk6#

带有选项“-P”的pkill应有助于:

pkill -P $(pgrep some_monitor1.sh)

来自手册页:

-P ppid,...
          Only match processes whose parent process ID is listed.

www.example.com上有一些讨论linuxquests.org,请查看:
http://www.linuxquestions.org/questions/programming-9/use-only-one-kill-to-kill-father-and-child-processes-665753/

dly7yett

dly7yett7#

我喜欢下面这个直截了当的方法:用一个环境变量来启动子进程,环境变量有一些名字/值,然后用它来终止子进程。最方便的方法是使用正在运行的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
uttx8gqw

uttx8gqw8#

与上面类似,只是做了一个小的调整,以杀死ps指示的所有进程:

ps -o pid= | tail -n +2 | xargs kill -9

也许草率/脆弱,但乍一看似乎工作。依赖于事实,目前的过程($$)往往是第一线。
命令说明,按顺序排列:
1.打印当前油库中流程的PID,不包括标题列
1.从2号线开始(不包括当前终端 shell )
1.杀了那些机器人

x6yk4ghg

x6yk4ghg9#

我已经将答案中的一系列建议合并到一个函数中,它为进程提供退出时间,如果进程花费太长,则将其删除,并且不必通过输出进行grep(例如,通过ps

#!/bin/bash
# This function will kill all sub jobs.
function KillJobs() {
  [[ -z "$(jobs -p)" ]] && return # no jobs to kill
  local SIG="INT" # default to a gentle goodbye
  [[ ! -z "$1" ]] && SIG="$1" # optionally send a different signal
  # my version of 'kill' doesn't seem to understand `kill -- -${PID}`
  #jobs -p | xargs -I%% kill -s "$SIG" -- -%% # kill each job's processes group
  jobs -p | xargs kill -s "$SIG" # kill each job's processes group
  
  ## give the processes a moment to die, before forcing them to.
  [[ "$SIG" != "KILL" ]] && {
    sleep 0.2
    KillJobs "KILL"
  }
}

我也尝试过用pkill做一个变种,但是在我的系统(xubuntu21.10)上,它什么也没做。

#!/bin/bash
# This function doesn't seem to work.
function KillChildren() {
  local SIG="INT" # default to a gentle goodbye
  [[ ! -z "$1" ]] && SIG="$1" # optionally send a different signal
  pkill --signal "$SIG" -P $$ # kill descendent's and their processes groups
  [[ "$SIG" != "KILL" ]] && {
    # give them a moment to die before we force them to.
    sleep 0.2
    KillChildren "KILL" ;
  }
}

相关问题