4

When writing a bash script, which is better to chain commands, a semicolon ; or double ampersand &&?

Eliah Kagan
  • 119,640

1 Answers1

12

As steeldriver says, neither is better than the other. You use them for different purposes.

Use ; if you want to run one command, then another. The second command will run regardless of whether or not the first one succeeded. Separating commands with a ; achieves the same goal as running one command, and then running the other one. In a script, these achieve the same goal:

first-command
second-command
first-command; second-command

In contrast, && checks the exit status of the first command, and only runs the second command if the first command succeeded. In shell scripting (and when you are using a shell interactively, too), an an exit code of 0 is taken to mean "true" or "success," while any other exit code is taken to mean "false," or "failure." (That way, programs can return different error codes to signify different kinds of errors.)

So, here, as before, first-command runs first. But if it does't succeed, then second-command is not run at all:

first-command && second-command

This is similar to, but not exactly the same as, using if:

if first-command; then
    second-command
fi

The way they are different lies in what happens when first-command fails. With &&, the entire compound command's exit status is whatever failing (i.e., nonzero) exit code first-command returned. In contrast, with if, the entire compound command's exit status is zero (i.e., success) when first-command fails.


As an example of a situation where you might actually reasonably consider both ; and &&, suppose you wanted to run sudo apt update, which retrieves up-to-date information about what packages are available from each of your configured software sources and at what versions, followed by sudo apt upgrade, to upgrade your installed packages to their latest available versions. This is widely suggested, and is what I usually run:

sudo apt update && sudo apt upgrade

Because it uses &&, it runs sudo apt update, but only runs sudo apt upgrade if sudo apt update reported that it succeeded. The reason you would usually want this, in the case of those particular commands, is that you would usually want to inspect any errors that the first command produced in order to decide how to proceed.

But you might expect a problem but still want to upgrade what packages you could. Or you might not expect a problem but just prefer to proceed ahead anyway. In that situation, you could separate them with ; (or just put them on separate lines, in a script):

sudo apt update; sudo apt upgrade

That runs sudo apt update, then runs sudo apt upgrade regardless of whether or not it reported succeeding.

This works as an example of a situation where you might actually be choosing between the two, because it is a case where the first command is important for the second one, but where the second one might still be useful even if the first one failed. However, in many situations where you want to run one command and then another, you either have:

  • No dependence of the second command on the first, where if the first fails, you still want to run the second one and its ability to succeed is expected not to be affected. Then you will usually use ; or place them on separate lines of a script.
  • Complete dependence of the second command on the first, such that it would make no sense--or be actively harmful--to attempt the second command if the first had failed. Then you will want to use && to separate them.

By the way, there is also a || operator. This runs the second command only if the first command failed rather than only if it succeeded (as with &&):

first-command || second-command

|| should not be confused with |, which sets up a pipe between commands.

Eliah Kagan
  • 119,640