This is my solution using job control.
- Whenever a job dies, it kills the parent script
- When the parent script dies, it kill the whole process group, including all jobs
I would hope that there's something simpler out there.
#!/usr/bin/env bash
# Mocks
function process () {
while true ; do
echo "Process 1ドル is working..."
sleep 10
done
}
# Actual implementation
trap terminate_entire_process_group EXIT
function terminate_entire_process_group () {
trap - EXIT
kill -15 -$$
}
function terminate_parent_process () {
trap - EXIT
kill $$ 2> /dev/null
}
(
trap terminate_parent_process EXIT
process 1
) &
(
trap terminate_parent_process EXIT
process 2
) &
wait
1 Answer 1
This is clear and readable code - nice work.
Current style is to use portable syntax to define functions (i.e. omitting the function
keyword). I recommend you stick to that.
If you're happy for all background tasks to terminate the process group (rather than having some which should and some which shouldn't), then we can just wait for the first background task to exit, using wait -n
. It might also be a good idea to pass -f
here, in case any child is stopped and restarted.
It might be necessary to send SIGKILL
to processes that fail to exit on signal 15 (but prefer to use the symbolic name here - -TERM
- or just omit it, since that's the default signal).
We can't be sure that the shell has its own process group (when I run it from Make, then Make itself is the process group leader, and kill -$$
is an error). Similarly, if the shell has job control enabled, then each background job will be leader of its own process group.
It might be better to list the jobs and target the signal at the children exactly:
kill_children() {
#echo "Killing children" $(jobs -l | cut -d' ' -f2) >&2
# assuming GNU xargs
jobs -l | cut -d' ' -f2 | xargs --no-run-if-empty kill
}
trap kill_children EXIT
process 1 &
process 2 &
process 3 &
wait -fn