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

时间:2008-12-24 18:48:00

标签: linux shell process signals

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

33 个答案:

答案 0 :(得分:283)

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

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

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

答案 1 :(得分:188)

使用 流程组ID PGID

杀死属于同一流程树的所有流程

  • kill -- -$PGID 使用默认信号(TERM = 15)
  • kill -9 -$PGID 使用信号KILL(9)

您可以从同一进程树的进程ID PGID)中检索PID

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

特别感谢tanagerSpeakus$PID剩余空间和OSX兼容性的贡献。

说明

  • kill -9 -"$PGID" =>向所有孩子和孙子发送信号9(KILL)......
  • PGID=$(ps opgid= "$PID") =>从树的任何 Process-ID 中检索 Process-Group-ID ,而不仅仅是 Process-Parent-ID ps opgid= $PID 的变体是 ps -o pgid --no-headers $PID ,其中 pgid 可以替换为 {{ 1}} 即可。
    但是:
    • pgrp ps少于五位时插入前导空格,并在tanager注意时右对齐。您可以使用: PID
    • 来自OSX的
    • PGID=$(ps opgid= "$PID" | tr -d ' ') 始终打印标题,因此Speakus建议: ps
  • PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )" 仅打印连续数字(不打印空格或字母标题)。

更多命令行

grep -o [0-9]*

限制

  • davideHubert Kario注意到,当属于同一棵树的进程调用 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) 时, kill 在终止整个树杀死之前自杀的风险。
  • 因此,请务必使用具有不同 Process-Group-ID 的流程运行该命令。

长篇故事

kill

使用'&'

在后台运行流程树
> 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 不会杀死孙子:

pkill -P $PID

命令> 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 -- -$PGID

结论

我注意到此示例中> 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 PID相等(PGID)。
这就是为什么我原本认为28957就够了。但是,如果进程在kill -- -$PID内生成,则进程ID 组ID 不同。

我认为 Makefile 是从不同的组ID (另一个进程树)调用时杀死整个进程树的最佳简单技巧。

答案 2 :(得分:164)

pkill -TERM -P 27888

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

或更强大:

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

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

请参阅this answer以终止所有后代。

答案 3 :(得分:99)

要以递归方式终止进程树,请使用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) <pid> [signal]"
    exit 1
fi

killtree $@

答案 4 :(得分:16)

来自 rkill 程序包的

pslist 命令将给定信号(或默认为nextTuple())发送到指定进程及其所有后代:

SIGTERM

答案 5 :(得分:11)

布拉德的回答也是我推荐的,除非你使用awk选项--ppid完全取消ps

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

答案 6 :(得分:9)

如果你知道传递父进程的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

答案 7 :(得分:9)

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

所以它看起来像那样:

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

其中24901是父级的PID。

它看起来很丑陋,但它完美地完成了工作。

答案 8 :(得分:9)

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

答案 9 :(得分:8)

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

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

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

答案 10 :(得分:8)

要添加Norman Ramsey的答案,如果您想创建一个流程组,可能值得查看setsid。
http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html

  

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

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

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

答案 11 :(得分:7)

ysth’s comment启发

kill -- -PGID
  

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

之前

答案 12 :(得分:5)

以下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
}

答案 13 :(得分:5)

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

def killChildren(pid):
    parent = psutil.Process(pid)
    for child in parent.get_children(True):
        if child.is_running():
            child.terminate()

答案 14 :(得分:4)

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

init_killtree() {
    local pid=$1 child

    for child in $(pgrep -P $pid); do
        init_killtree $child
    done
    [ $pid -ne $$ ] && kill -kill $pid
}

答案 15 :(得分:4)

如果要按名称终止进程:

killall -9 -g someprocessname

pgrep someprocessname | xargs pkill -9 -g

答案 16 :(得分:3)

这是我使用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//,/ }

答案 17 :(得分:3)

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

答案 18 :(得分:1)

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

我的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

答案 19 :(得分:1)

老问题,我知道,但所有的回答似乎都在继续调用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,我想。

答案 20 :(得分:1)

我进一步开发了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

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

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

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

答案 21 :(得分:1)

以下内容已在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

答案 22 :(得分:0)

如果您知道要杀死的东西的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 )))

答案 23 :(得分:0)

现在要进行一些聪明的shell编程。

此解决方案有一定的成本,但至少是基于日常迭代和递归的。可以通过仔细注意typeset命令并将其转换为declarelocal(如果适用)来将其转换为bash。

讨论

杀死一个进程时,必须处理这样一个现实,即它可能是许多孩子的父母,而每个孩子都可能成为更多孩子的父母,并且持续不断。

做什么?

如果只有一个函数可以测试一个进程是否具有子进程,而另一个函数可以返回父进程的子PID。

然后,该游戏将变得更加简单,因为您可以创建一个循环来遍历一系列PID,在杀死每个PID之前先检查每个孩子。如果没有孩子,请杀死该进程。如果有孩子,则递归调用驱动函数,并将该函数的结果传递给该函数,该函数将获取父母孩子的PID。

基本案例操作(进程没有子级)。

#!/bin/ksh

function killProcess ()
{
    typeset -r PID=$1

    if [[ ! isProcess $PID ]]
    then
        echo -e "Process $PID cannot be terminated because it does not exist.\n" 1>&2
        return 1
    elif [[ kill -s TERM $PID ]] && [[ ! isProcess $PID ]]
    then
        echo -e "Process $PID was terminated.\n" 1>&2
        return 0
    elif kill -s KILL $PID
        echo -e "Process $PID killed with SIGKILL (9) signal. No time to clean up potential files.\n" 1>&2
        return 0
    elif isZombie $PID
    then
        echo -e "Process $PID in the zombie status.\n" 1>&2 
        return 2
    else
        echo -e "Process $PID is alive. SIGTERM and SIGKILL had no effect. It is not a zombie.\n" 1>&2
    fi

    return 3
}

function attemptToKillPid ()
{
    typeset -r PID=$1

    if killProcess $PID
    then 
        return 0
    fi

    ppid=$(getParentPid $pid)
    echo -e "Process $pid of parent $ppid was not able to be killed.\n" 1>&2
    return 1
}

一般案例操作(流程有子级)。

function killPidFamily ()
{
    typeset -r PROCESSES=$*
    typeset -ir NUM_PROCESSES_TO_KILL=$(countLines $PROCESSES)
    typeset -i numKilledProcesses=0
    typeset ppid

    for pid in $PROCESSES
    do
        pid=$(trim $pid)

        if ! hasChildPids $pid
        then
            attemptToKillPid $pid && (( numKilledProcesses++ ))
        else
            killPidFamily $(getChildPids $pid) && attemptToKillPid $pid && (( numKilledProcesses++ ))
        fi
    done

    (( numKilledProcesses == NUM_PROCESSES_TO_KILL ))
    return $?
}

支持功能库。

#!/bin/ksh

function trim ()
{
    echo -n "$1" | tr -d [:space:]
}

function countLines ()
{
    typeset -r $LIST=$*
    trim $(echo $LIST | wc -l | awk {'print $1'})
}

function getProcesses ()
{
    # NOTE: -o pgid below would be $4 in awk.

    ps -e -o comm,pid,ppid,pgid,user,ruid,euid,group,rgid,egid,etime,etimes,stat --no-headers
}

function getProcess ()
{
   typeset -r PID=$1
   ps -p $PID -o comm,pid,ppid,pgid,user,ruid,euid,group,rgid,egid,etime,etimes,stat --no-headers
}

function isProcess ()
{
    typeset -r PID=$1

    ps -p $PID -o pid --no-headers 1>&2
    return $?
}

function getProcessStatus ()
{
    typeset -r PID=$1
    trim $(ps -p $PID -o stat --no-headers)
}

function isZombie ()
{
    typeset -r PID=$1
    typeset processStatus

    processStatus=$(getProcessStatus $PID)

    [[ "$processStatus" == "Z" ]]
    return $?
}

function hasChildPids ()
{
    typeset -r PPID=$1
    echo $(getProcesses) | awk '{print $3}' | sort -n | uniq | grep "^${PPID}$"
    return $?
}

function getChildPids ()
{
    typeset -r PPID=$1
    echo $(getProcesses) | awk '{print $2, $3}' | sort -k 2 | awk "\$2 == $PPID {print \$1}" | sort -n
}

function getParentPid ()
{
    typeset -r PID=$1
    trim $(echo $(getProcess $PID) | awk '{print $3}')
}

通过这种方式,您可以肯定地知道进程树正在从分支中被破坏 ,并向上移动到根 。这有助于避免产生僵尸和其他不良情况的可能性。

现在,您已经看到了执行此操作的最昂贵的方法(一次杀死一个进程),研究如何更改此解决方案以使用PGID(进程组ID)。 getProcesses ()函数已经可以打印PGID($4中的awk),因此请学习如何使用它或不使用它。

答案 24 :(得分:0)

仅使用属于该组的进程名称杀死该组:

kill -- -$(ps -ae o pid,pgrp,cmd | grep "[e]xample.py" | awk '{print $2}' | tail -1)

这是对olibre答案的修改,但您无需知道PID,只需知道组成员的姓名即可。

说明:

要获取组ID,请使用如图所示的参数执行ps命令,对命令进行grep格式化,然后使用引号对example.py进行格式化,并使用首字母括弧(这会过滤掉grep命令本身),然后通过awk对其进行过滤,以获取第二个字段,即组ID。尾部-1消除了重复的组ID。您可以使用$()语法将所有内容都放入变量中,瞧–您可以获得组ID。因此,您可以用$(mess)代替上面的-groupid。

答案 25 :(得分:0)

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

killtree() { 
    for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
        echo Terminating: $p 
        kill $p
    done
}

答案 26 :(得分:0)

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

# 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
}

干杯。

答案 27 :(得分:0)

此脚本也有效:

#/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

答案 28 :(得分:0)

在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;

并观看名称为&#39; test&#39;在其他终端使用以下命令。

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

上面的脚本将创建4个新的子进程及其父进程。每个子进程将运行10秒。但是一旦达到5秒的超时,相应的父进程将杀死这些孩子。 因此孩子无法完成执行(10秒)。 玩这些时间(开关10和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;

并观看名称为&#39; test&#39;在其他终端使用以下命令。

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

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

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

更多细节可以在这里找到,

Killing child process in shell script

答案 29 :(得分:0)

在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

答案 30 :(得分:0)

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

答案 31 :(得分:0)

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

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

答案 32 :(得分:-3)

键入ps -ef检查进程ID。 通过键入kill -9 <pid>

来终止该过程