Убить все процессы, принадлежащие одному и тому же дереву процессов , используя ID группы процессов (PGID
)
kill -- -$PGID
Использовать сигнал по умолчанию (TERM
= 15)
kill -9 -$PGID
Использовать сигнал KILL
(9)
Вы можете извлечь PGID
из любого идентификатора процесса (PID
) того же дерева процессов
kill -- -$(ps -o pgid= $PID | grep -o '[0-9]*')
(сигнал TERM
)
kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*')
(сигнал KILL
)
Особая благодарность tanager и Speakus за вклад в $PID
оставшиеся пробелы и совместимость с OSX.
Объяснение
kill -9 -"$PGID"
=> Послать сигнал 9 (KILL
) всем детям и внукам ...
PGID=$(ps opgid= "$PID")
=> Получить ID группы процессов из любого ИД процесса дерева, а не только Процесс- родитель-ID . Вариант ps opgid= $PID
равен ps -o pgid --no-headers $PID
, где pgid
можно заменить на pgrp
.
Но:
ps
вставляет начальные пробелы, когда PID
меньше пяти цифр и выровнено по правому краю, как заметил tanager . Вы можете использовать:
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)
Ограничение
- Как отметили Давид и Хьюберт Карио , когда
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
Заключение
Я заметил, что в этом примере PID
и PGID
равны (28957
).
Вот почему я изначально думал, что kill -- -$PID
достаточно. Но в случае, если процесс запускается в Makefile
, ID процесса отличается от ID группы .
Я думаю, kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)
- лучший простой способ убить все дерево процессов при вызове из другого ID группы (другое дерево процессов).