Kill your Kids
Not literally, of course. This is programming talk, those of you who aren’t programmers can let your eyes glaze over.
I wanted a script to start a bunch of little servers, then wait around for them to finish or when the user interrupts with Ctrl-C, clean up the servers instead of orphaning them. I wanted to propagate the SIGINT to the child processes. I wanted to kill the kids.
The simple way, if you just want to make sure the kids are killed and you don’t care how:
sleep 300 &
# etc.
trap "kill $(echo $(jobs -p)) 2>/dev/null" EXIT
wait
If you only want to trap SIGINT and want to make sure you send SIGINT (not SIGKILL) to the children, then you want to do something like:
trap "kill -INT $(echo $(jobs -p)) 2>/dev/null" INT
wait
Update: I was asked by a shell scripting guru why I needed to do $(echo $(jobs -p)) and not just $(jobs -p). I intended to cover that but forgot. The reason is that $(jobs -p) has newlines and while that’s not usually a problem it is in a trap statement, because it’s evaluated at creation time not at run time. It also means that processes created after you create the trap wouldn’t be killed. Then, he suggested a function instead. Pure brilliance. Where does he come up with these things? Here’s the improved version:
function killkids() { kill $(jobs -p); }
trap "killkids" EXIT
You can still redirect stderr if you want to, but the reason I was directing stderr was because some of the kids may have already died (early evaluation remember) and then kill would needlessly complain. This way, it kills all the kids that are still alive, none more none less.
July 6th, 2009 at 13:00
This is another situation where ” isn’t the same as ‘
If you define your trap with “…” then the variables will be evaluated during the definition. If, instead, you use ‘…’ then the variables (i.e. your list of children) will be evaluated only when the trap fires.
This snippet shows the trivial case. Use kill to send either 1, 2, or 15 to show the point.
S=0
trap ‘echo trap 1 with S=$S – delayed’ 1
trap “echo trap 2 with S=$S – immediate” 2
S=1
while :
do
echo pid $$ waiting for signal 1, 2, or 15
sleep 2
S=$((S+1))
done