[linux] 프로세스 그룹의 모든 구성원에게 신호를 보내는 가장 좋은 방법은 무엇입니까?

전체 프로세스 트리를 죽이고 싶습니다. 일반적인 스크립팅 언어를 사용하여이를 수행하는 가장 좋은 방법은 무엇입니까? 간단한 해결책을 찾고 있습니다.



답변

죽이고 자하는 트리가 단일 프로세스 그룹인지는 말할 수 없습니다. (트리가 서버 시작 또는 쉘 명령 행에서 분기 된 결과 인 경우가 종종 있습니다.) 다음과 같이 GNU ps를 사용하여 프로세스 그룹을 발견 할 수 있습니다.

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

강제 종료하려는 프로세스 그룹 인 경우 kill(1)명령을 사용 하지만 프로세스 번호를 지정하는 대신 그룹 번호를 무시 하십시오. 예를 들어 그룹 5112의 모든 프로세스를 종료하려면을 사용하십시오 kill -TERM -- -5112.


답변

프로세스 그룹 ID ( )를 사용하여 동일한 프로세스 트리에 속하는 모든 프로세스를 종료하십시오.PGID

  • kill -- -$PGID     기본 신호 사용 ( TERM= 15)
  • kill -9 -$PGID     신호를 사용하십시오 KILL(9)

동일한 프로세스 트리Process-ID ( ) PGID에서 를 검색 할 수 있습니다.PID

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

남은 공간과 OSX 호환성 에 기여한 tanagerSpeakus 에게 특별한 감사를드립니다 $PID.

설명

  • kill -9 -"$PGID"=> KILL모든 어린이와 손자 에게 신호 9 ( )를 보냅니다 .
  • PGID=$(ps opgid= "$PID")=> Process-Parent-ID 뿐만 아니라 트리의 모든 Process -ID 에서 Process-Group-ID 를 검색합니다 . 의 변형 IS 에 의해 대체 될 수있다 . 그러나:

    ps opgid= $PIDps -o pgid --no-headers $PIDpgidpgrp

    • pstanager에서 알 수PID 있듯이 5 자리 미만이고 오른쪽으로 정렬 되면 선행 공백을 삽입합니다 . 당신이 사용할 수있는:
      PGID=$(ps opgid= "$PID" | tr -d ' ')
    • psOSX에서 항상 헤더를 인쇄하므로 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)

한정

  • davideHubert 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

결론

I는이 예에서 통지 PID하고 PGID(동일하다 28957).
이것이 내가 처음 kill -- -$PID에는 충분 하다고 생각한 이유 입니다. 그러나 경우에 프로세스는 내 산란되는 프로세스 ID가 로부터 다른 그룹 ID .Makefile

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 초 후에 살해를 계획하고 프로세스 종료를 정중하게 요청합니다.

모든 자손을 종료하려면 이 답변 을 참조하십시오 .


답변

프로세스 트리를 재귀 적으로 종료하려면 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 $@


답변

pslist 패키지의 rkill 명령은 지정된 신호 (또는SIGTERM기본적으로)를 지정된 프로세스 및 모든 하위 항목으로보냅니다.

rkill [-SIG] pid/name...


답변

브래드의 대답은 내가 너무 좋습니다 당신이 멀리 할 수 있다는 점을 제외하고 줄 것입니다 awk당신이 사용하는 모두 경우 --ppid에 옵션을 ps.

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


답변

부모 프로세스의 pid를 전달하는 것을 알고 있다면 다음과 같이 작동하는 쉘 스크립트가 있습니다.

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