How do I kill background processes / jobs when my shell script exits?
To clean up some mess, trap
can be used. It can provide a list of stuff executed when a specific signal arrives:
trap "echo hello" SIGINT
but can also be used to execute something if the shell exits:
trap "killall background" EXIT
It's a builtin, so help trap
will give you information (works with bash). If you only want to kill background jobs, you can do
trap 'kill $(jobs -p)' EXIT
Watch out to use single '
, to prevent the shell from substituting the $()
immediately.
This works for me (improved thanks to the commenters):
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
kill -- -$$
sends a SIGTERM to the whole process group, thus killing also descendants.Specifying signal
EXIT
is useful when usingset -e
(more details here).
Update: https://stackoverflow.com/a/53714583/302079 improves this by adding exit status and a cleanup function.
trap "exit" INT TERM
trap "kill 0" EXIT
Why convert INT
and TERM
to exit? Because both should trigger the kill 0
without entering an infinite loop.
Why trigger kill 0
on EXIT
? Because normal script exits should trigger kill 0
, too.
Why kill 0
? Because nested subshells need to be killed as well. This will take down the whole process tree.