我想杀死整个进程树。使用通用脚本语言实现这一目标的最佳方法是什么?我在寻找一个简单的解决办法。


当前回答

下面的代码已经在FreeBSD, Linux和MacOS X上进行了测试,只依赖于pgrep和kill (ps -o版本在BSD下不工作)。第一个参数是父pid,子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

这将向shell脚本中的任何子/孙辈进程发送SIGTERM,如果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

其他回答

要递归地杀死进程树,请使用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 $@

在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
ps -o pid= --ppid $PPID | xargs kill -9 

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

Use

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//,/ }

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

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

欢呼。