10

I've encountered a headache problem.

I want to execute mulitple commands in background, so I want to start them in bash one by one. It's easy to start one command in linux shell in background, just like this:

myCommand &

It's also easy to start multiple commands, just like this:

myCommand1 && myCommand2

or

myCommand1 ; myCommand2

But if I want to run multiple commands in background, I tried the following command format, but failed:

myCommand1 & && myCommand2 &

or

myCommand1 & ; myCommand2 &

Both formats fail. How can I run multiple commands which have & in one command line?

  • 2
    Put them in a script and run the script in the background – Panther Dec 29 '17 at 3:41
  • 1
  • Panther, it seems using () could help fix this issue much easier than using a script. Let's try to make full use of the features provided by the shell itself firstly, instead of composing what we want by ourselves. But of course, using script also could fix this issue. Thanks anyway. – Clock ZHONG Jan 11 '18 at 17:14
  • What if I want to run a 'tail -F <file1> > <file2>' followed by 'jobs -l', which is again followed by 'disown -h %1' – akskap Apr 30 '18 at 13:09
19

Use ().

If you want to run them sequentially:

(myCommand1; myCommand2) &

or

(myCommand1 &) && (myCommand2 &)

If you want them to run parallel:

myCommand1 & myCommand2 &

In bash you can also use this (space behind the { and the ; are mandatory):

{ myCommand1 && myCommand2; } &
  • 3
    (myCommand1 &) && (myCommand2 &) will run myCommand2 even if myCommand1 failed. – terdon Dec 29 '17 at 9:15
  • () could help bash to distinguish the & and &&. So just use () to seperate the execution unit when we want to use the & and && togather. – Clock ZHONG Dec 30 '17 at 14:09
15

I suppose you want this:

myCommand1 & myCommand2 &

This starts myCommand1 and sends it to the background as it's followed by ampersand, then immediately starts myCommand2 and sends also this to the background, therefore releasing the shell again.

Lists

For better understanding you may substitute pipeline by command here.

A list is a sequence of one or more pipelines separated by one of the operators ;, &, &&, or ||, and optionally terminated by one of ;, &, or .

If a command is terminated by the control operator &, the shell executes the command in the background in a subshell. The shell does not wait for the command to finish, and the return status is 0. Commands separated by a ; are executed sequentially; the shell waits for each command to terminate in turn. The return status is the exit status of the last command executed.

AND and OR lists are sequences of one or more pipelines separated by the && and || control operators, respectively.
Source: man bash

Let's break that down into examples. You can build a list by combining commands and separating them with one of these: ; & && ||:

command1 ; command2  # runs sequentially
command1 && command2 # runs sequentially, runs command2 only if command1 succeeds
command1 || command2 # runs sequentially, runs command2 only if command1 fails
command1 & command2  # runs simultaneously

You can terminate lists with one of these: ; & <newline>.
Normally you execute a command or a list by pressing Enter, that equals <newline>. The semicolon ; serves the very same purpose especially in scripts. Ampersand & however starts the command(s) in a subshell in the background, immediately releasing the shell.

You can use round () or curly brackets {} to further group lists, the difference being that round brackets spawn a subshell and curly ones don't. Curly brackets need a space after the first and a semicolon or a newline before the closing bracket. For example:

# if c1 succeeds start a shell in the background
# and run c2 and c3 sequentially inside it
c1 && ( c2 ; c3 ) & 
# run c1 and if it succeeds c2 sequentially as a group command
# if c1 or c2 fail run c3 in the background
{ c1 && c2 ;} || c3 &

This can get quite complicated, if you're unsure use true and false to test whether the construction works as expected:

$ { true && true ;} || echo 2
$ { true && false ;} || echo 2
2

Job Control

The jobs command displays a list of the background jobs that are running or have recently been finished in the current shell. There are a number of keyboard shortcuts and commands for job control:

  • Ctrl+Z types the suspend character that causes the process currently running in the foreground to be stopped, it is not terminated, but remains in the jobs list
  • Ctrl+Y types the delayed suspend character that causes the process currently running in the foreground to be stopped when it attempts to read input from the terminal
  • fg = % brings a process into the foreground starting it if necessary, you can specify the process as follows:

     %       # last process in the jobs list
     %1      # 1st process in the jobs list
     %abc    # process beginning with the string “abc”
     %?abc   # process containing the string “abc” anywhere
    
  • bg = %& takes a process into the background starting it if necessary:

     %&      # last process in the jobs list
     %1&     # 1st process in the jobs list
     %abc&   # process beginning with the string “abc”
     %?abc&  # process containing the string “abc” anywhere
    
  • wait waits for a background process to be finished and returns its termination status:

     wait %1 # 1st process in the jobs list
    

    Imagine you started a lengthy process (jobs reveals it's number 3) and then realize you want the computer to be suspended when it finishes, plus echo a message if the process didn't succeed:

     wait %3 || echo failed ; systemctl suspend
    
  • But important to be careful with && it is dependent on what the command returns, so we need to be sure that whatever we call actually returns something bash considers a truthy value ..? – mathreadler Dec 29 '17 at 19:17
  • @mathreadler Unless you're talking about some poorly made user script the exit value is very well defined (see man bash) and broadly used exactly as it's intended AFAIK – I never experienced anything weird. – dessert Dec 29 '17 at 20:01
  • exactly, one should be careful about poorly made user scripts. They do exist and can be a pain to find such bugs. Askubuntu does not allow me to "@ dessert" you. – mathreadler Dec 29 '17 at 20:11
  • Ah okay, that makes sense now that you mention it. – mathreadler Dec 29 '17 at 20:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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