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?
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.