[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 호환성 에 기여한 tanager 와 Speakus 에게 특별한 감사를드립니다 $PID
.
설명
kill -9 -"$PGID"
=>KILL
모든 어린이와 손자 에게 신호 9 ( )를 보냅니다 .PGID=$(ps opgid= "$PID")
=> Process-Parent-ID 뿐만 아니라 트리의 모든 Process -ID 에서 Process-Group-ID 를 검색합니다 . 의 변형 IS 에 의해 대체 될 수있다 . 그러나:ps opgid= $PID
ps -o pgid --no-headers $PID
pgid
pgrp
ps
tanager에서 알 수PID
있듯이 5 자리 미만이고 오른쪽으로 정렬 되면 선행 공백을 삽입합니다 . 당신이 사용할 수있는:
PGID=$(ps opgid= "$PID" | tr -d ' ')
ps
OSX에서 항상 헤더를 인쇄하므로 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)
한정
- davide 와 Hubert 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 $@
답변
답변
브래드의 대답은 내가 너무 좋습니다 당신이 멀리 할 수 있다는 점을 제외하고 줄 것입니다 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
