I want to kill a whole process tree. What is the best way to do this using any common scripting languages? I am looking for a simple solution.
The killpg() function sends a signal to a process group. A process has permission to send a signal if the real or effective user ID of the sender is the same as the real or effective user ID of the intended recipient. A process can also send signals if it has appropriate privileges.
Pkill Command – Send signal to the process based on its name. You can send signal to any process by specifying the full name or partial name.
Kill is used to send a signal to a process. The most commonly used signal is "terminate" (SIGTERM) or "kill" (SIGKILL).
If the process is privileged, send the signal to all processes except for some special system processes. Otherwise, send the signal to all processes with the same effective user ID. A process can send a signal to itself with a call like kill (getpid(), signum ) .
You don't say if the tree you want to kill is a single process group. (This is often the case if the tree is the result of forking from a server start or a shell command line.) You can discover process groups using GNU ps as follows:
ps x -o "%p %r %y %x %c "
If it is a process group you want to kill, just use the kill(1)
command but instead of giving it a process number, give it the negation of the group number. For example to kill every process in group 5112, use kill -TERM -- -5112
.
Kill all the processes belonging to the same process tree using the Process Group ID (PGID
)
kill -- -$PGID
Use default signal (TERM
= 15)kill -9 -$PGID
Use the signal KILL
(9)You can retrieve the PGID
from any Process-ID (PID
) of the same process tree
kill -- -$(ps -o pgid= $PID | grep -o '[0-9]*')
(signal TERM
)kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*')
(signal KILL
)Special thanks to tanager and Speakus for contributions on $PID
remaining spaces and OSX compatibility.
kill -9 -"$PGID"
=> Send signal 9 (KILL
) to all child and grandchild...PGID=$(ps opgid= "$PID")
=> Retrieve the Process-Group-ID from any Process-ID of the tree, not only the Process-Parent-ID. A variation of ps opgid= $PID
is ps -o pgid --no-headers $PID
where pgid
can be replaced by pgrp
. ps
inserts leading spaces when PID
is less than five digits and right aligned as noticed by tanager. You can use:PGID=$(ps opgid= "$PID" | tr -d ' ')
ps
from OSX always print the header, therefore Speakus proposes:PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
grep -o [0-9]*
prints successive digits only (does not print spaces or alphabetical headers).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
is invoked by a process belonging to the same tree, kill
risks to kill itself before terminating the whole tree killing.> 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 the process tree in background using '&'
> ./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
The command pkill -P $PID
does not kill the grandchild:
> 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
The command kill -- -$PGID
kills all processes including the grandchild.
> 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 notice in this example PID
and PGID
are equal (28957
).
This is why I originally thought kill -- -$PID
was enough. But in the case the process is spawn within a Makefile
the Process ID is different from the Group ID.
I think kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)
is the best simple trick to kill a whole process tree when called from a different Group ID (another process tree).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With