22

Am I correct to assume that when ; joins two commands on a line, Bash always waits until the first command has exited before executing the second command? And similarly, in a shell script containing two different commands on different lines, Bash always waits until the command on the first line has exited before executing the command on the second line?

If this is the case, is there a way to execute two commands in one line or in a script, so that the second command doesn't wait until the first command has finished?

Also, are different lines in a shell script equivalent to separate lines joined by ; or &&?

EmmaV
  • 4,067

4 Answers4

33

You're correct, commands in scripts are executed sequentially by default.

You can run a command in the background by suffixing it with & (a single ampersand).

Commands on separate lines are equivalent to commands joined with ; by default. If you tell your shell to abort on non-zero exit codes (set -e), then the script will execute as though all the commands were joined with &&.

Stephen Kitt
  • 434,908
4

To answer your second question, you can use & to launch a command in the background and continue with the script without waiting for it to finish.

commandA & commandB

If you run this at an interactive terminal (instead of a script), you can use fg to bring the backgrounded command back into focus, or jobs to see a list of background tasks.

rmelcer
  • 525
1

In the simplest scenario, when you have full control over the previous process you can chain the next command with firstCommand && secondCommand as already mentioned in other answers. The syntaxis implies that firstCommand assumes responsibility for returning a correct exit code (0 on success and non-zero on failure), and that secondCommand will only run if firstCommand exited successfully.

When you do not have control over firstCommand or when it's already running, or when firstCommand does not return sane exit codes on success/failure then you can poll for running processes every N seconds and start secondCommand after the first one exits:

while true ; do pgrep firstCommand && echo 'Still running...' || secondCommand ; sleep 1 ; done

❗️ CAVEAT: secondCommand will run even if firstCommand finished with a non-zero exit status.

Also see:

ccpizza
  • 1,723
  • Other answers did not mention && at all. You seem to solve a problem that is not part of this question. – Kusalananda Dec 02 '21 at 10:10
  • @they the task is to run commandA after commandB and my answer solves it in more than one way; the accepted answer does mention && — and that is the generic and correct approach; i have provided an answer for a corner case which cannot be solved with && – ccpizza Dec 02 '21 at 10:33
  • @they: also please be aware that this question (closed) https://unix.stackexchange.com/questions/184502/bash-how-to-run-a-command-after-the-previous-finished/184503 redirects to this one, and my answer is directly relevant to that question – ccpizza Dec 02 '21 at 10:46
  • Hmm. I think that's a bad duplicate, actually. This question is asking how to run two commands asynchronously, while the dupe is about whether ; makes the second command wait for the first. So your answer is indeed a good answer for Bash - how to run a command after the previous finished?, but not really for this question here. I don't want to reopen the dupe since the top answer there is mine, but I have asked the other mods to take a look. – terdon Dec 03 '21 at 12:09
  • @terdon: thanks! indeed, the question is on a slightly different topic, but the title is how most users will run into this post; imo the original issue that the poster had is less relevant that the topic of Consecutive commands which is probably what most visitors would be interested in. – ccpizza Dec 03 '21 at 17:37
1

As others said, you have to add & sign at the end of command that should run in background.

If you want a script to complete all tasks simultaneously and then exit, just add "wait" command at the end of the script. In such scenario, bash is waiting for all commands to finish until it goes any further.

Jacek
  • 31