Linux 什么';向流程组的所有成员发送信号的最佳方式是什么?

Linux 什么';向流程组的所有成员发送信号的最佳方式是什么?,linux,shell,process,signals,Linux,Shell,Process,Signals,我想杀死一棵完整的进程树。使用任何通用脚本语言执行此操作的最佳方法是什么?我正在寻找一个简单的解决方案。如果您知道传递父进程的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 do

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

如果您知道传递父进程的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的答案也是我推荐的,除了如果您使用
--ppid
选项来
ps
,您可以完全取消
awk

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

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

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

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

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

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

干杯。

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

ps -o pid= --ppid $PPID | xargs kill -9 
#/bin/bash
基尔特里(){
本地_pid=$1
局部_sig=${2:--TERM}
kill-stop${u-pid}需要停止在子杀死和父杀死之间快速分叉父对象以生成子对象
对于{u child in$(ps-opid--no headers--ppid${u pid});do
killtree${u child}${u sig}
完成
kill-${u sig}${u pid}
}
如果[$#-eq 0-o$#-gt 2];然后
echo“用法:$(基本名称$0)[信号]”
出口1
fi
基尔特里$@

如果您的系统上有pstree和perl,您可以尝试以下方法:

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

在孩子出生之前杀死父母可能更好;否则,父母可能会在自杀前再次生育新的子女。这些将在杀戮中幸存下来

我的ps版本与上述版本不同;也许太老了,所以奇怪的灰色

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

然而,这基本上是一个想法



如果你知道你想要杀死的东西的pid,你通常可以从会话id和同一会话中的所有内容开始。我会仔细检查,但我用这个脚本在我想要终止的循环中启动rsync,而不是像我刚刚终止所有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 )))
这将杀死所有父进程ID为27888的进程

或更稳健:

CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS
它会在33秒后停止,并礼貌地要求进程终止


有关终止所有子体的信息,请参阅。

要添加到Norman Ramsey的答案中,如果要创建进程组,可能需要查看setId。

函数的作用是创建一个 新会话,如果调用进程为 不是流程组长。在上面 返回调用过程应为 本次新会议的会议负责人 会话,应为过程组 新流程小组组长,以及 应无控制终端。 调用进程的进程组ID 工艺设置应等于 调用进程的进程ID。这个 调用过程应是唯一的 新流程组中的流程和 新会话中唯一的进程

我认为这意味着你可以从一开始就创建一个组。我在php中使用它是为了能够在启动整个进程树之后杀死它


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

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

使用

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 `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " "`
其中,24901是母公司的PID


它看起来很难看,但做得很好。

修改了志刚的答案:

#!/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
灵感来自

与其给它一个进程号,不如给它一个组的否定
号码。和通常的任何命令一样,如果你想要一个正常的参数 以不被解释为开关的
-
开头,在其前面加上
-


使用进程组ID
PGID
)杀死属于同一进程树的所有进程

  • 终止--$PGID
    使用默认信号(
    术语
    =15)
  • kill-9-$PGID
    使用信号
    kill
    (9)
您可以从同一进程树的任何进程ID(
PID
)中检索
PGID

  • kill--$(ps-o pgid=$PID | grep-o'[0-9]*')
    (信号
    术语
  • kill-9-$(ps-o pgid=$PID | grep-o'[0-9]*')
    (信号
    kill
特别感谢您对
$PID
剩余空间和OSX兼容性的贡献

解释
  • kill-9-“$PGID”
    =>向所有子代和孙代发送信号9(
    kill
  • PGID=$(ps opgid=“$PID”)
    =>从树的任何进程ID检索进程组ID,不仅是进程-Parent-ID。
    ps opgid=$PID
    的一个变体是
    ps-o pgid——没有头$PID
    ,其中
    pgid
    可以被
    pgrp
    替换
    但是:
    • ps
      PID
      小于五位且右对齐时插入前导空格,如所注意到的。您可以使用:
      PGID=$(ps opgid=“$PID”| tr-d”)
    • ps
      来自OSX a
      killtree.sh PID SIGNAL
      
      #!/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 `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " "`
      
      #!/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
      
      kill -- -PGID
      
      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)
      
      > 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"
      ./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"  # 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
      
      killtree() {
          local parent=$1 child
          for child in $(ps -o ppid= -o pid= | awk "\$1==$parent {print \$2}"); do
              killtree $child
          done
          kill $parent
      }
      
      def killChildren(pid):
          parent = psutil.Process(pid)
          for child in parent.get_children(True):
              if child.is_running():
                  child.terminate()
      
      kill -- -$( ps opgid= $PID | tr -d ' ' )
      
      init_killtree() {
          local pid=$1 child
      
          for child in $(pgrep -P $pid); do
              init_killtree $child
          done
          [ $pid -ne $$ ] && kill -kill $pid
      }
      
      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"
      }
      
      killall -9 -g someprocessname
      
      pgrep someprocessname | xargs pkill -9 -g
      
      for SIGNAL in TERM KILL; do
        for CHILD in $(jobs -s|sort -r); do
          kill -s $SIGNAL $CHILD
          sleep $MOMENT
        done
      done
      
      #!/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;
      
      watch -n1 'ps x -o "%p %r %c" | grep "test" '
      
      #!/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;
      
      watch -n1 'ps x -o "%p %r %c" | grep "test" '
      
      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
      
      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
      
      rkill [-SIG] pid/name...
      
       #!/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
      
      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)}'
      
      sub(/[0-9]*/, "", p)
      
      killtree() { 
          for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
              echo Terminating: $p 
              kill $p
          done
      }