In Bash, how can I run multiple infinitely-running commands and cancel them all with ^C?
I'll let Admiral Ackbar answer this one.
#!/bin/bash -erun_development_webserver.sh &PIDS[0]=$!watch_sass_files_and_compile_them.sh &PIDS[1]=$!watch_coffeescript_files_and_compile_them.sh & PIDS[2]=$!trap "kill ${PIDS[*]}" SIGINTwait
This starts each of your commands in the background (&
), puts their process ids ($!
) into an array (PIDS[x]=$!
), tells bash
to kill
them all (${PIDS[*]
) when your script gets a SIGINT
signal (Ctrl+C), and then wait
s for all the processes to exit.
And I'll proactively mention that "kill ${PIDS[*]}"
expands PIDS
when you create the trap
; if you change the double quotes ("
) to single quotes ('
), it will be expanded when the trap
is executed, which means you can add more processes to PIDS
after you set the trap
and it will kill them too.
If you have a stubborn process that doesn't want to quit after a Ctrl+C (SIGINT
), you may need to send it a stronger kill signal - SIGTERM
or even SIGKILL
(use this as a last resort, it unconditionally kills the process without giving it a chance to clean up). First, try changing the trap
line to this:
trap "kill -TERM ${PIDS[*]}" SIGINT
If it doesn't respond to the SIGTERM
, save that process's pid separately, say in STUBBORN_PID
, and use this:
trap "kill ${PIDS[*]}; kill -KILL $STUBBORN_PID" SIGINT
Remember, this one won't let the stubborn process clean up, but if it needs to die and isn't, you may need to use it anyway.