Exiting a shell script if certain child processes exit

I have a Bash script that starts one web server, does some work, and then starts a second web server. I would like the script to exit, and for both of these servers to be terminated, if either server exits or the user types Ctrl+C.

What I have now looks like this:

start_server_1 &
server_1_pid=$!

trap "kill $server_1_pid" EXIT

# ...do some work that requires server 1 to be running...

start_server_2 || exit $?

This correctly shuts down both servers if the user types Ctrl+C. If Server 1 exits, however, then Server 2 and the script itself continue to run. How can I make sure that both servers and the script will be taken down if one of these processes exits?

Answer

Run both processes in the background, then wait -n to wait for one of them to exit.

Bash doesn’t report back which process exited, but you can run jobs -p to get the list of background jobs that are still running and kill them.

start_server_1 &
server_1_pid=$!
start_server_2 &
server_2_pid=$!
wait -n
kill $(jobs -p)

wait -n is new in bash 4.3. In older versions, doing this is much more difficult.

Other common shells don’t have wait -n, but they instead let you set a trap on SIGCHLD and call plain wait. In dash, ksh93, mksh and zsh, you can write

trap 'kill $server_1_pid $server_2_pid; exit' CHLD
wait

This doesn’t work in bash because there the SIGCHLD trap is only invoked after all jobs have finished running.

Leave a Reply

Your email address will not be published. Required fields are marked *