23

How is it possible to run multiple commands and background them using bash?

For example:

$ for i in {1..10}; do wait file$i &; done

where wait is a custom binary.

Right now I get an error:

syntax error near unexpected token `;'

when running the above command.

Once backgrounded the commands should run in parallel.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
Sebi
  • 999
  • 5
  • 16
  • 29
  • 1
    Am ashuming your not referring to: `nohup` allowing you to execute a command in the background – Dave Hamilton Mar 23 '16 at 16:03
  • 3
    The error you're seeing is due to `&` and `;` are both "command terminators". You don't need to use both: `for ...; do wait $arg & done` will work. – glenn jackman Mar 23 '16 at 16:07
  • @glenn jackman. Yes, I actually tried it after posting the question. There is no need for both ; and & – Sebi Mar 23 '16 at 16:08
  • 3
    For future readers, [a link to the documentation](https://www.gnu.org/software/bash/manual/bashref.html#Lists): "A list is a sequence of one or more pipelines separated by one of the operators ‘;’, ‘&’, ‘&&’, or ‘||’, and optionally terminated by **one** of ‘;’, ‘&’, or a newline." (emphasis mine) – glenn jackman Mar 23 '16 at 16:12
  • http://stackoverflow.com/q/14753491/560648 – Lightness Races in Orbit Mar 24 '16 at 01:32

4 Answers4

32

The &, just like ; is a list terminator operator. They have the same syntax and can be used interchangeably (depending on what you want to do). This means that you don't want, or need, command1 &; command2, all you need is command1 & command2.

So, in your example, you could just write:

for i in {1..10}; do wait file$i & done

and each wait command will be launched in the background and the loop will immediately move on to the next.

terdon
  • 234,489
  • 66
  • 447
  • 667
4

For the sake of compatibility use the posix form instead of expansion:

for i in $(seq 1 10); do (./wait file$i &); done
marc
  • 2,317
  • 2
  • 16
  • 25
  • 2
    Note that `seq` is not a POSIX command and is generally only found on GNU systems. The behaviour or `$(...)` (and `$i`) depends on the current value of `$IFS`. Also note that by doing `(cmd &)`, `cmd` will be a child of a subshell, so you won't be able to wait for and get its exit status for instance. – Stéphane Chazelas Mar 23 '16 at 20:32
2

You can group the commands and put the grouped commands in background. Like :

$ for i in {1..10}; do ((wait file$i)&); done
magor
  • 3,592
  • 2
  • 11
  • 27
  • There is no need to use the inner parentheses... – marc Mar 23 '16 at 15:44
  • only need to use the inner parentheses if you want to put in the background multiple commands as asked in the question. Like ((sleep 1; wait file$i)&); – magor Mar 23 '16 at 16:17
2

Is your binary really named wait? I don't recommend to do so, because wait is a shell builtin.

I believe bash doesn't parse well a one-line loop that launches background processes. I suggest you to change the code to:

$ for i in {1..10}; do ./wait file$i & echo "Running 'wait' using PID=$!..."; done