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

我想杀死整个进程树。 使用任何常用的脚本语言来做这件事的最好方法是什么? 我正在寻找一个简单的解决方案。


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

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

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


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

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

  • kill -- -$(ps -o pgid= $PID | grep -o '[0-9]*') (signal TERM
  • kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*') (signal KILL
  • 特别感谢Tanager和Speakus对$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可以被pgrp替换。
    但:
  • PID小于5位时, ps插入前导空格,并且如tanager所注意的那样右对齐。 您可以使用:
    PGID=$(ps opgid= "$PID" | tr -d ' ')
  • 来自OSX的ps总是打印标题,因此Speakus提出:
    PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
  • 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)
    

    局限性

  • 由于注意到了达维德和休伯特Kario,当kill由属于同一棵树的过程调用, kill风险终止整个树杀害前杀死自己。
  • 因此,请确保使用具有不同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
    

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

    结论

    我注意到在这个例子中PIDPGID是相等的( 28957 )。
    这就是为什么我原本以为kill -- -$PID就足够了。 但是如果进程在Makefile产生,进程ID与组ID不同。

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


    pkill -TERM -P 27888
    

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

    或更健壮:

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

    该计划在33秒之后安排杀戮,并礼貌地要求进程终止。

    看到这个答案终止所有的后代。

    链接地址: http://www.djcxy.com/p/49667.html

    上一篇: What's the best way to send a signal to all members of a process group?

    下一篇: What's the best way to trim std::string?