Friday, May 15, 2009

Recursive Kill: Kill a Process Tree

As far as I know, killing a process should also kill its children - the signal is supposed to be propagated from the parent process to its children. But, sometimes this doesn't seem to work.

Here's a script that sends a SIGKILL (9) signal to all the processes with process ids provided as arguments, and to all their child processes, going from child processes up to their parents:

#!/bin/bash

dokill() {
for cpid in $(ps -o pid= --ppid $1)
do
dokill $cpid
done
echo "killing: $(ps -p $1 -o cmd=)"
kill -9 $1 > /dev/null 2>&1
}

if [[ $# == 0 ]]; then
echo "usage: $(basename $0) <top pid to kill>"
exit 1
fi

for pid in $*
do
dokill $pid
done

Recursion rules!

(credits: this is based on a script that I found at the comp.unix.shell newsgroup archive)

3 comments:

  1. Very elegant. Unfortunately, does not work on a Mac that uses the BSD version of ps (doesn't have a --pid) option.

    ReplyDelete
  2. I assume you're actually referring to the --ppid option.

    On Debian you can replace the line after dokill() with the following:
    for cpid in $(/bin/ps --no-heading -A -f | awk -v ppid=$1 '($3==ppid){print $2}')
    to get a similar effect.

    A bit cumbersome, but hopefully works on Mac too.

    ReplyDelete
  3. Somehow the kill hung on a WCHAN=pipe_w.
    This is working in such cases, in my situation...:
    dokill() {
    for cpid in $(ps -o pid= --ppid $1)
    do
    dokill $cpid
    done
    if [ ! "x$(ps -o wchan= -p $1)" = "xpipe_wait" ]; then
    kill -s 9 $1 > /dev/null 2>&1
    fi
    }

    ReplyDelete