How can I run multiple commands which have & in one command line?

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?


Solution 1:

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; } &

Solution 2:

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