Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Bash, how can I run multiple infinitely-running commands and cancel them all with ^C?

I would like to write a script that runs a few different infinitely running commands, e.g.

run_development_webserver.sh
watch_sass_files_and_compile_them.sh
watch_coffeescript_files_and_compile_them.sh

I'd like to run each of them in parallel, and kill them all by hitting ^C. Is this possible, and if so how can I do this?

like image 371
Rudd Zwolinski Avatar asked Jan 26 '12 18:01

Rudd Zwolinski


People also ask

How do you stop a loop in bash?

Bash break Statement The break statement ends the current loop iteration and exits from the loop. When combined with a condition, break helps provide a method to exit the loop before the end case happens. The Bash break statements always apply to loops. The integer value is optional, and it is 1 by default.

How do you run multiple commands at once?

Using Semicolon (;) Operator to Run Multiple Linux commands. The semicolon (;) operator enables you to run one or more commands in succession, regardless of whether each earlier command succeeds or not. For example, run the following three commands on one line separated by semicolons (;) and hit enter.

How do I stop a true bash?

Infinite while Loop You can also use the true built-in or any other statement that always returns true. The while loop above will run indefinitely. You can terminate the loop by pressing CTRL+C .


1 Answers

I'll let Admiral Ackbar answer this one.

trap

#!/bin/bash -e

run_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[*]}" SIGINT

wait

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

like image 183
Kevin Avatar answered Oct 05 '22 04:10

Kevin