Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want to run two commands simultaneously in bash on a Linux machine. Therefore in my ./execute.sh bash script I put:

command 1 & command 2
echo "done"

However when I want to stop the bash script and hit Ctrl+C, only the second command is stopped. The first command keeps running. How do I make sure that the complete bash script is stopped? Or in any case, how do I stop both commands? Because in this case no matter how often I press Ctrl+C the command keeps running and I am forced to close the terminal.

share|improve this question
    
Make the follow up question into a separate question and remove here. Now it is unclear for a visitor if both question was answered, or just the intial question. –  Zelda Jan 7 at 8:59

4 Answers 4

up vote 5 down vote accepted

If you type

command 1 & command 2

this is equal to

command 1 &
command 2

i.e. this will run the first command in background and then runs the second command in foreground. Especially this means, that your echo "done" is printed after command 2 finished even if command 1 is still running.

You probably want

command 1 &
command 2 &
wait
echo "done"

This will run both commands in background and wait for both to complete.


If you press CTRL-C this will only send the SIGINT signal to the foreground process, i.e. command 2 in your version or wait in my version.

I would suggest setting a trap like this:

#!/bin/bash

trap killgroup SIGINT

killgroup(){
  echo killing...
  kill 0
}

loop(){
  echo $1
  sleep $1
  loop $1
}

loop 1 &
loop 2 &
wait

With the trap the SIGINT signal produced by CTRL-C is trapped and replaced by the killgroup function, which kills all those processes.

share|improve this answer
    
Thank you for your answer! I do however have a follow-up question. I now have the following script: trap killgroup SIGINT killgroup(){ echo killing... kill 0 } command001 command1 & command2 I have ommitted the wait command because the script is allowed to continue when command2 is finished. However it seems that command 1 already starts when I run the script. Can I fix this? Thanks –  maero21 Jan 3 at 22:35
    
command1 starts directly after command001 is finished. you can use set -x at the beginning of your script to print the commands that are executed. –  michas Jan 4 at 0:03

When putting a command into the background from a script, the PID is not displayed on the screen. The builtin variable $! stores the PID of the last process so you can capture the PID of command1 using it.

command1 &
echo $!

would echo the PID of command1.

Bash also provides the trap builtin which you can use to register a sequence of commands to run when particular signals are received. You can use this to catch the SIGINT and kill command1 before exiting the main script e.g.

#!/bin/bash

onINT() {
echo "Killing command1 $command1PID too"
kill -INT "$commad1PID"
exit
}

trap "onINT" SIGINT
command1 &
command1PID="$!"
comamnd2
echo Done

Now, whilst command 2 is running, hitting Ctrl C will cause both command1 and command2 to be sent SIGINT.

share|improve this answer
    
You can also use %n syntax to kill specific background jobs in this shell. Usually you issue kill %1 to kill the latest and the only background process. With more background processes, use jobs to see the list first. –  9000 Jan 1 at 15:29
    
@9000: Yes but the OP is running their commands in a script (./execute.sh) so getting jobs to work is much more problematic surely ? –  Iain Jan 1 at 15:33
    
@lain: certainly. I missed the point about the running from a script. –  9000 Jan 1 at 16:50

Ctrl + C sends a SIGINT signal to your front process, which is command2. command1 is run in background, therefore not concerned by the input stream.

When you type command1 &, bash should give you the process' PID, something like [1234]. To kill this process, you can use kill 1234. Now, if you have the PIDs of both command1 and command2 (have a look at ps -ef), you can use kill to terminate them all :

kill pid1 pid2 pid3 ...

A little trick would be to run both commands in background, with :

command1 & command2 &

Bash will give you both PIDs, ready to get killed. Another trick would be to bring back command1 in the foreground once you killed command2 :

command1 & command2
# Hit Ctrl+C : command2 terminates.

fg # Bring back command1 to foreground.
# Hit Ctrl+C again, command1 terminates.

More info available here : http://linuxg.net/how-to-manage-background-and-foreground-processes/

share|improve this answer

Newer versions of GNU Parallel will do what you want:

parallel ::: "command 1" "command 2"
echo "done"

Or if command remains the same:

parallel command ::: 1 2
echo done

Watch the intro video for a quick introduction: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Walk through the tutorial (man parallel_tutorial). You command line with love you for it.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.