linux信号嵌套,linux - 向进程组的所有成员发送信号的最佳方法是什么?

linux - 向进程组的所有成员发送信号的最佳方法是什么?

我想杀死整个进程树。 使用任何常用脚本语言执行此操作的最佳方法是什么? 我正在寻找一个简单的解决方案。

30个解决方案

276 votes

您没有说要杀死的树是否是单个进程组。 (如果树是从服务器启动或shell命令行分叉的结果,则通常会出现这种情况。)您可以使用GNU ps发现进程组,如下所示:

ps x -o "%p %r %y %x %c "

如果它是您要杀死的进程组,只需使用kill(1)命令,但不要给它一个进程号,而是给它取消组号。 例如,要杀死组5112中的每个进程,请使用kill -TERM -- -5112。

Norman Ramsey answered 2019-01-24T13:27:13Z

176 votes

使用进程组ID(kill -- -$(ps -o pgid= $PID | grep -o [0-9]*))终止属于同一进程树的所有进程

kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)使用默认信号(kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) = 15)

kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)使用信号kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)(9)

您可以从同一进程树的任何进程ID(PGID)中检索kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)

kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)(信号kill -- -$(ps -o pgid= $PID | grep -o [0-9]*))

kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)(信号kill -- -$(ps -o pgid= $PID | grep -o [0-9]*))

特别感谢tanager和Speakus对kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)剩余空间和OSX兼容性的贡献。

说明

kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) => 向所有子孙发送信号9(kill -- -$(ps -o pgid= $PID | grep -o [0-9]*))...

kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) => 从树的任何Process-ID中检索Process-Group-ID,而不仅仅是Process-Parent-ID。 kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)的变体是kill -- -$(ps -o pgid= $PID | grep -o [0-9]*),其中kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)可以替换为kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)。

但:kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)在kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)小于五位数时插入前导空格,并在唐纳德注意到时右对齐。 您可以使用:

kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)

来自OSX的kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)始终打印标题,因此Speakus建议:

kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)

kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)仅打印连续数字(不打印空格或字母标题)。

更多命令行

PGID=$(ps -o pgid= $PID | grep -o [0-9]*)

kill -TERM -"$PGID" # kill -15

kill -INT -"$PGID" # correspond to [CRTL+C] from keyboard

kill -QUIT -"$PGID" # correspond to [CRTL+\] from keyboard

kill -CONT -"$PGID" # restart a stopped process (above signals do not kill it)

sleep 2 # wait terminate process (more time if required)

kill -KILL -"$PGID" # kill -9 if it does not intercept signals (or buggy)

局限性

正如davide和Hubert Kario所注意到的,当属于同一棵树的进程调用kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)时,kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)可能会在终止整个树杀死之前自行终止。

因此,请确保使用具有不同Process-Group-ID的进程运行该命令。

很长的故事

> cat run-many-processes.sh

#!/bin/sh

echo "ProcessID=$$ begins ($0)"

./child.sh background &

./child.sh foreground

echo "ProcessID=$$ ends ($0)"

> cat child.sh

#!/bin/sh

echo "ProcessID=$$ begins ($0)"

./grandchild.sh background &

./grandchild.sh foreground

echo "ProcessID=$$ ends ($0)"

> cat grandchild.sh

#!/bin/sh

echo "ProcessID=$$ begins ($0)"

sleep 9999

echo "ProcessID=$$ ends ($0)"

使用'&'在后台运行流程树

> ./run-many-processes.sh &

ProcessID=28957 begins (./run-many-processes.sh)

ProcessID=28959 begins (./child.sh)

ProcessID=28958 begins (./child.sh)

ProcessID=28960 begins (./grandchild.sh)

ProcessID=28961 begins (./grandchild.sh)

ProcessID=28962 begins (./grandchild.sh)

ProcessID=28963 begins (./grandchild.sh)

> PID=$! # get the Parent Process ID

> PGID=$(ps opgid= "$PID") # get the Process Group ID

> ps fj

PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND

28348 28349 28349 28349 pts/3 28969 Ss 33021 0:00 -bash

28349 28957 28957 28349 pts/3 28969 S 33021 0:00 \_ /bin/sh ./run-many-processes.sh

28957 28958 28957 28349 pts/3 28969 S 33021 0:00 | \_ /bin/sh ./child.sh background

28958 28961 28957 28349 pts/3 28969 S 33021 0:00 | | \_ /bin/sh ./grandchild.sh background

28961 28965 28957 28349 pts/3 28969 S 33021 0:00 | | | \_ sleep 9999

28958 28963 28957 28349 pts/3 28969 S 33021 0:00 | | \_ /bin/sh ./grandchild.sh foreground

28963 28967 28957 28349 pts/3 28969 S 33021 0:00 | | \_ sleep 9999

28957 28959 28957 28349 pts/3 28969 S 33021 0:00 | \_ /bin/sh ./child.sh foreground

28959 28960 28957 28349 pts/3 28969 S 33021 0:00 | \_ /bin/sh ./grandchild.sh background

28960 28964 28957 28349 pts/3 28969 S 33021 0:00 | | \_ sleep 9999

28959 28962 28957 28349 pts/3 28969 S 33021 0:00 | \_ /bin/sh ./grandchild.sh foreground

28962 28966 28957 28349 pts/3 28969 S 33021 0:00 | \_ sleep 9999

28349 28969 28969 28349 pts/3 28969 R+ 33021 0:00 \_ ps fj

命令kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)不会杀死孙子:

> pkill -P "$PID"

./run-many-processes.sh: line 4: 28958 Terminated ./child.sh background

./run-many-processes.sh: line 4: 28959 Terminated ./child.sh foreground

ProcessID=28957 ends (./run-many-processes.sh)

[1]+ Done ./run-many-processes.sh

> ps fj

PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND

28348 28349 28349 28349 pts/3 28987 Ss 33021 0:00 -bash

28349 28987 28987 28349 pts/3 28987 R+ 33021 0:00 \_ ps fj

1 28963 28957 28349 pts/3 28987 S 33021 0:00 /bin/sh ./grandchild.sh foreground

28963 28967 28957 28349 pts/3 28987 S 33021 0:00 \_ sleep 9999

1 28962 28957 28349 pts/3 28987 S 33021 0:00 /bin/sh ./grandchild.sh foreground

28962 28966 28957 28349 pts/3 28987 S 33021 0:00 \_ sleep 9999

1 28961 28957 28349 pts/3 28987 S 33021 0:00 /bin/sh ./grandchild.sh background

28961 28965 28957 28349 pts/3 28987 S 33021 0:00 \_ sleep 9999

1 28960 28957 28349 pts/3 28987 S 33021 0:00 /bin/sh ./grandchild.sh background

28960 28964 28957 28349 pts/3 28987 S 33021 0:00 \_ sleep 9999

命令kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)杀死包括孙子在内的所有进程。

> kill -- -"$PGID" # default signal is TERM (kill -15)

> kill -CONT -"$PGID" # awake stopped processes

> kill -KILL -"$PGID" # kill -9 to be sure

> ps fj

PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND

28348 28349 28349 28349 pts/3 29039 Ss 33021 0:00 -bash

28349 29039 29039 28349 pts/3 29039 R+ 33021 0:00 \_ ps fj

结论

我注意到在这个例子中kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)和PGID是相等的(28957)。

这就是为什么我原本以为kill -- -$PID就够了。 但是,如果进程在Makefile中生成,则进程ID与组ID不同。

我认为kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)是从不同的组ID(另一个进程树)调用时杀死整个进程树的最佳简单技巧。

olibre answered 2019-01-24T13:30:28Z

160 votes

pkill -TERM -P 27888

这将终止具有父进程ID 27888的所有进程。

或者更强大:

CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS

计划在33秒后杀人并礼貌地要求程序终止。

请参阅此答案以终止所有后代。

Onlyjob answered 2019-01-24T13:31:14Z

99 votes

要以递归方式终止进程树,请使用killtree():

#!/bin/bash

killtree() {

local _pid=$1

local _sig=${2:--TERM}

kill -stop ${_pid} # needed to stop quickly forking parent from producing children between child killing and parent killing

for _child in $(ps -o pid --no-headers --ppid ${_pid}); do

killtree ${_child} ${_sig}

done

kill -${_sig} ${_pid}

}

if [ $# -eq 0 -o $# -gt 2 ]; then

echo "Usage: $(basename $0) [signal]"

exit 1

fi

killtree $@

zhigang answered 2019-01-24T13:31:38Z

15 votes

来自pslist包的rkill命令将给定信号(或默认情况下为SIGTERM)发送到指定进程及其所有后代:

rkill [-SIG] pid/name...

Onlyjob answered 2019-01-24T13:32:01Z

11 votes

布拉德的答案也是我推荐的,除非您使用--ppid选项218773280198911929,否则您可以完全取消awk。

for child in $(ps -o pid -ax --ppid $PPID) do ....... done

Kim Stebel answered 2019-01-24T13:32:24Z

9 votes

如果你知道传递父进程的pid,这里是一个应该工作的shell脚本:

for child in $(ps -o pid,ppid -ax | \

awk "{ if ( \$2 == $pid ) { print \$1 }}")

do

echo "Killing child process $child because ppid = $pid"

kill $child

done

brad.lane answered 2019-01-24T13:32:47Z

9 votes

我使用了这里描述的方法的一点修改版本:[https://stackoverflow.com/a/5311362/563175]

所以看起来像这样:

kill `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " "`

其中24901是父母的PID。

它看起来很丑陋,但它的工作完美无缺。

Tomasz Werszko answered 2019-01-24T13:33:29Z

9 votes

zhigang的修改版答案:

#!/usr/bin/env bash

set -eu

killtree() {

local pid

for pid; do

kill -stop $pid

local cpid

for cpid in $(pgrep -P $pid); do

killtree $cpid

done

kill $pid

kill -cont $pid

wait $pid 2>/dev/null || true

done

}

cpids() {

local pid=$1 options=${2:-} space=${3:-}

local cpid

for cpid in $(pgrep -P $pid); do

echo "$space$cpid"

if [[ "${options/a/}" != "$options" ]]; then

cpids $cpid "$options" "$space "

fi

done

}

while true; do sleep 1; done &

cpid=$!

for i in $(seq 1 2); do

cpids $$ a

sleep 1

done

killtree $cpid

echo ---

cpids $$ a

x-yuri answered 2019-01-24T13:33:53Z

8 votes

要添加Norman Ramsey的答案,如果要创建进程组,可能值得查看setsid。

[http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html]

setsid()函数应创建一个   新会话,如果调用进程是   不是流程组的领导者。上   返回调用进程应该是   这个新会议的领导者   会话,应该是进程组   新流程组的领导者,以及   没有控制终端。   调用的进程组ID   过程应设置为等于   调用进程的进程ID。该   呼叫过程应该是唯一的   新流程组中的流程和   新会话中唯一的进程。

我认为这意味着您可以从启动过程创建一个组。 我在php中使用它,以便能够在启动后杀死整个进程树。

这可能是一个坏主意。 我对评论很感兴趣。

hajamie answered 2019-01-24T13:34:46Z

8 votes

我无法评论(声誉不够),所以我被迫添加一个新的答案,即使这不是一个真正的答案。

@olibre在2月28日给出的非常好的和彻底的答案存在一些问题.ps opgid= $PID的输出将包含短于5位的PID的前导空格,因为ps证明了该列的合理性(严格对齐数字)。 在整个命令行中,这会产生一个负号,后跟空格,然后是组PID。 简单的解决方案是管道ps到tr删除空格:

kill -- -$( ps opgid= $PID | tr -d ' ' )

tanager answered 2019-01-24T13:35:16Z

6 votes

受到ysth评论的启发

kill -- -PGID

而不是给它一个进程号,给它否定该组   数。 像往常几乎任何命令一样,如果你想要一个正常的参数   以-开头,不能解释为开关,先于--

Steven Penny answered 2019-01-24T13:35:47Z

5 votes

以下shell函数类似于许多其他答案,但它适用于Linux和BSD(OS X等),没有外部依赖,如pgrep:

killtree() {

local parent=$1 child

for child in $(ps -o ppid= -o pid= | awk "\$1==$parent {print \$2}"); do

killtree $child

done

kill $parent

}

David Röthlisberger answered 2019-01-24T13:36:10Z

5 votes

使用psutil使用python执行此操作非常容易。 只需使用pip安装psutil,然后就可以使用一整套流程操作工具:

def killChildren(pid):

parent = psutil.Process(pid)

for child in parent.get_children(True):

if child.is_running():

child.terminate()

genericdave answered 2019-01-24T13:36:32Z

4 votes

根据志刚的回答,这可以避免自杀:

init_killtree() {

local pid=$1 child

for child in $(pgrep -P $pid); do

init_killtree $child

done

[ $pid -ne $$ ] && kill -kill $pid

}

davide answered 2019-01-24T13:36:55Z

4 votes

如果要按名称终止进程:

killall -9 -g someprocessname

要么

pgrep someprocessname | xargs pkill -9 -g

Mika Vatanen answered 2019-01-24T13:37:19Z

3 votes

这是我使用bash脚本杀死所有子进程的版本。它不使用递归并依赖于pgrep命令。

使用

killtree.sh PID SIGNAL

killtrees.sh的内容

#!/bin/bash

PID=$1

if [ -z $PID ];

then

echo "No pid specified"

fi

PPLIST=$PID

CHILD_LIST=`pgrep -P $PPLIST -d,`

while [ ! -z "$CHILD_LIST" ]

do

PPLIST="$PPLIST,$CHILD_LIST"

CHILD_LIST=`pgrep -P $CHILD_LIST -d,`

done

SIGNAL=$2

if [ -z $SIGNAL ]

then

SIGNAL="TERM"

fi

#do substring from comma to space

kill -$SIGNAL ${PPLIST//,/ }

marekdef answered 2019-01-24T13:37:53Z

3 votes

这是@ zhigang的答案的变体,没有AWK,只依赖于Bash的原生解析可能性:

function killtree {

kill -STOP "$1"

ps -e -o pid= -o ppid= | while read -r pid ppid

do

[[ $ppid = $1 ]] || continue

killtree "$pid" || true # Skip over failures

done

kill -CONT "$1"

kill -TERM "$1"

}

它似乎在Mac和Linux上运行良好。 在您不能依赖于能够管理进程组的情况下 - 例如在编写用于测试必须在多个环境中构建的软件的脚本时 - 这种树行走技术肯定是有帮助的。

solidsnack answered 2019-01-24T13:38:23Z

1 votes

在孩子面前杀死父母可能更好; 否则父母可能会在他自己被杀之前再次产生新的孩子。 这些将在杀戮中存活下来

我的ps版本与上面的版本不同; 也许太旧了,因此奇怪的贪图......

使用shell脚本而不是shell函数有很多优点......

然而,这基本上是志刚的想法

#!/bin/bash

if test $# -lt 1 ; then

echo >&2 "usage: kiltree pid (sig)"

fi ;

_pid=$1

_sig=${2:-TERM}

_children=$(ps j | grep "^[ ]*${_pid} " | cut -c 7-11) ;

echo >&2 kill -${_sig} ${_pid}

kill -${_sig} ${_pid}

for _child in ${_children}; do

killtree ${_child} ${_sig}

done

Peter Steier answered 2019-01-24T13:39:07Z

1 votes

以下内容已在FreeBSD,Linux和MacOS X上测试过,仅依赖于pgrep和kill(ps -o版本在BSD下不起作用)。 第一个参数是父pid,其中孩子必须被终止。 第二个参数是一个布尔值,用于确定父pid是否也必须终止。

KillChilds() {

local pid="${1}"

local self="${2:-false}"

if children="$(pgrep -P "$pid")"; then

for child in $children; do

KillChilds "$child" true

done

fi

if [ "$self" == true ]; then

kill -s SIGTERM "$pid" || (sleep 10 && kill -9 "$pid" &)

fi

}

KillChilds $$ > /dev/null 2>&1

这会将SIGTERM发送到shell脚本中的任何子/孙进程,如果SIGTERM不成功,它将等待10秒然后发送kill。

早期答案:

以下也有效,但会在BSD上杀死shell本身。

KillSubTree() {

local parent="${1}"

for child in $(ps -o pid=$parent); do

if [ $$ -ne $child ]; then (kill -s SIGTERM $child || (sleep 10 && kill -9 $child & )) > /dev/null 2>&1 ; fi

done

}

# Example lanch from within script

KillSubTree $$ > /dev/null 2>&1

deajan answered 2019-01-24T13:39:50Z

1 votes

我进一步开发了zhigang,xyuri和solidsneck的解决方案:

#!/bin/bash

if test $# -lt 1 ; then

echo >&2 "usage: kiltree pid (sig)"

exit 1 ;

fi ;

_pid=$1

_sig=${2:-TERM}

# echo >&2 "killtree($_pid) mypid = $$"

# ps axwwf | grep -6 "^[ ]*$_pid " >&2 ;

function _killtree () {

local _children

local _child

local _success

if test $1 -eq $2 ; then # this is killtree - don't commit suicide!

echo >&2 "killtree can´t kill it´s own branch - some processes will survive." ;

return 1 ;

fi ;

# this avoids that children are spawned or disappear.

kill -SIGSTOP $2 ;

_children=$(ps -o pid --no-headers --ppid $2) ;

_success=0

for _child in ${_children}; do

_killtree $1 ${_child} $3 ;

_success=$(($_success+$?)) ;

done ;

if test $_success -eq 0 ; then

kill -$3 $2

fi ;

# when a stopped process is killed, it will linger in the system until it is continued

kill -SIGCONT $2

test $_success -eq 0 ;

return $?

}

_killtree $$ $_pid $_sig

这个版本将避免杀死其祖先 - 这会导致先前解决方案中的大量子进程。

在确定子列表之前正确停止进程,以便不会创建或消除新的子项。

被杀后,停止的工作必须继续从系统中消失。

Peter Steier answered 2019-01-24T13:40:35Z

1 votes

老问题,我知道,但所有的回答似乎都在调用ps,我不喜欢。

这个基于awk的解决方案不需要递归,只调用ps一次。

awk 'BEGIN {

p=1390

while ("ps -o ppid,pid"|getline) a[$1]=a[$1]" "$2

o=1

while (o==1) {

o=0

split(p, q, " ")

for (i in q) if (a[q[i]]!="") {

p=p""a[q[i]]

o=1

a[q[i]]=""

}

}

system("kill -TERM "p)

}'

或者在单行上:

awk 'BEGIN {p=1390;while ("ps -o ppid,pid"|getline) a[$1]=a[$1]" "$2;o=1;while (o==1) {o=0;split(p, q, " ");for (i in q) {if (a[q[i]]!="") {p=p""a[q[i]];o=1;a[q[i]]=""}}}system("kill -TERM "p)}'

基本上我们的想法是我们构建一个父(子)条目的数组(a),然后围绕数组循环查找匹配父母的子项,并将它们添加到我们的父列表(p)中。

如果你不想杀死顶级进程,那么就做

sub(/[0-9]*/, "", p)

就在system()行将其从kill set中删除之前。

请记住,这里存在竞争条件,但所有解决方案都是如此(据我所见)。 它做我需要的东西,因为我需要它的脚本不会创造很多短命的孩子。

读者的练习是使其成为2遍循环:在第一遍之后,将SIGSTOP发送到p列表中的所有进程,然后循环再次运行ps,在第二遍之后发送SIGTERM,然后发送SIGCONT。 如果你不关心好的结局那么第二遍可能只是SIGKILL,我想。

Whinger answered 2019-01-24T13:41:55Z

1 votes

我知道那是旧的,但这是我找到的更好的解决方案:

killtree() {

for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do

echo Terminating: $p

kill $p

done

}

Luciano Andress Martini answered 2019-01-24T13:42:17Z

0 votes

感谢你的智慧,伙计们。 我的脚本在退出时留下了一些子进程,而否定提示使事情变得更容易。 我写了这个函数,以便在必要时在其他脚本中使用:

# kill my group's subprocesses: killGroup

# kill also myself: killGroup -x

# kill another group's subprocesses: killGroup N

# kill that group all: killGroup -x N

# N: PID of the main process (= process group ID).

function killGroup () {

local prid mainpid

case $1 in

-x) [ -n "$2" ] && kill -9 -$2 || kill -9 -$$ ;;

"") mainpid=$$ ;;

*) mainpid=$1 ;;

esac

prid=$(ps ax -o pid,pgid | grep $mainpid)

prid=${prid//$mainpid/}

kill -9 $prid 2>/dev/null

return

}

干杯。

answered 2019-01-24T13:42:43Z

0 votes

如果你的系统上有pstree和perl,你可以试试这个:

perl -e 'kill 9, (`pstree -p PID` =~ m/\((\d+)\)/sg)'

lyman answered 2019-01-24T13:43:05Z

0 votes

如果您知道要杀死的东西的pid,通常可以从会话ID和同一会话中的所有内容中获取。 我会仔细检查,但是我用这个脚本在我想要死的循环中启动rsyncs,而不是启动另一个(因为循环),因为如果我只是killall'd rsync。

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid 21709))

如果你不知道pid,你仍然可以嵌套更多

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid $(pgrep rsync )))

Morgan answered 2019-01-24T13:43:36Z

0 votes

ps -o pid= --ppid $PPID | xargs kill -9

Christian answered 2019-01-24T13:43:52Z

0 votes

在sh中,jobs命令将列出后台进程。 在某些情况下,最好先杀掉最新的进程,例如 较旧的一个创建了一个共享套接字。 在这些情况下,以相反的顺序对PID进行排序。 有时你想等待工作在磁盘上写东西或者在它们停止之前写东西。

如果你不需要,不要杀!

for SIGNAL in TERM KILL; do

for CHILD in $(jobs -s|sort -r); do

kill -s $SIGNAL $CHILD

sleep $MOMENT

done

done

jens answered 2019-01-24T13:44:22Z

0 votes

在shell脚本中杀死子进程:

很多时候我们需要杀死由于某种原因被绞死或阻塞的子进程。 例如。 FTP连接问题。

有两种方法,

1)为每个子节点创建单独的新父节点,一旦超时,将监视并终止子进程。

创建test.sh如下,

#!/bin/bash

declare -a CMDs=("AAA" "BBB" "CCC" "DDD")

for CMD in ${CMDs[*]}; do

(sleep 10 & PID=$!; echo "Started $CMD => $PID"; sleep 5; echo "Killing $CMD => $PID"; kill $PID; echo "$CMD Completed.") &

done

exit;

并使用以下命令观察在其他终端中名称为“test”的进程。

watch -n1 'ps x -o "%p %r %c" | grep "test" '

上面的脚本将创建4个新的子进程及其父进程。 每个子进程将运行10秒。 但是一旦达到5秒的超时,相应的父进程将杀死这些孩子。所以孩子将无法完成执行(10秒)。玩这些时间(开关10和5)以查看另一种行为。 在这种情况下,孩子将在5秒到达超时之前的5秒内完成执行。

2)当达到超时时,让当前父监视器并终止子进程。 这不会创建单独的父级来监视每个子级。 您还可以在同一父级中正确管理所有子进程。

创建test.sh如下,

#!/bin/bash

declare -A CPIDs;

declare -a CMDs=("AAA" "BBB" "CCC" "DDD")

CMD_TIME=15;

for CMD in ${CMDs[*]}; do

(echo "Started..$CMD"; sleep $CMD_TIME; echo "$CMD Done";) &

CPIDs[$!]="$RN";

sleep 1;

done

GPID=$(ps -o pgid= $$);

CNT_TIME_OUT=10;

CNT=0;

while (true); do

declare -A TMP_CPIDs;

for PID in "${!CPIDs[@]}"; do

echo "Checking "${CPIDs[$PID]}"=>"$PID;

if ps -p $PID > /dev/null ; then

echo "-->"${CPIDs[$PID]}"=>"$PID" is running..";

TMP_CPIDs[$PID]=${CPIDs[$PID]};

else

echo "-->"${CPIDs[$PID]}"=>"$PID" is completed.";

fi

done

if [ ${#TMP_CPIDs[@]} == 0 ]; then

echo "All commands completed.";

break;

else

unset CPIDs;

declare -A CPIDs;

for PID in "${!TMP_CPIDs[@]}"; do

CPIDs[$PID]=${TMP_CPIDs[$PID]};

done

unset TMP_CPIDs;

if [ $CNT -gt $CNT_TIME_OUT ]; then

echo ${CPIDs[@]}"PIDs not reponding. Timeout reached $CNT sec. killing all childern with GPID $GPID..";

kill -- -$GPID;

fi

fi

CNT=$((CNT+1));

echo "waiting since $b secs..";

sleep 1;

done

exit;

并使用以下命令观察在其他终端中名称为“test”的进程。

watch -n1 'ps x -o "%p %r %c" | grep "test" '

上面的脚本将创建4个新的子进程。 我们正在存储所有子进程的pid并循环遍历它们以检查它们是否已完成执行或仍在运行。子进程将执行到CMD_TIME时间。 但是如果CNT_TIME_OUT超时,所有孩子都会被父进程杀死。您可以切换时间并使用脚本来查看行为。这种方法的一个缺点是,它使用组ID来杀死所有子树。 但是父进程本身属于同一组,所以它也会被杀死。

如果您不希望父级被杀,您可能需要将其他组ID分配给父进程。

更多详情可在这找到,

在shell脚本中杀死子进程

Hemant Thorat answered 2019-01-24T13:46:11Z

0 votes

这个脚本也有效:

#/bin/sh

while true

do

echo "Enter parent process id [type quit for exit]"

read ppid

if [ $ppid -eq "quit" -o $ppid -eq "QUIT" ];then

exit 0

fi

for i in `ps -ef| awk '$3 == '$ppid' { print $2 }'`

do

echo killing $i

kill $i

done

done

Nullpointer answered 2019-01-24T13:46:41Z

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值