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.