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

- 117,780
1 Answers
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.

- 117,780
-
1A useful example is the following 'one-liner' to test if the computer is booted in UEFI or BIOS (alias legacy) mode:
test -d /sys/firmware/efi && echo efi || echo bios
– sudodus Apr 20 '18 at 20:15 -
1@sudodus You can use that but I don't consider it good technique. I recommend against trying to use
&&
and||
as a ternary conditional. Often the second command can fail; then the third runs. Evenecho
can fail, like if stdout is not writable (you can redirect to/dev/full
to simulate this). In that command, ifecho efi
fails thenecho bios
should also fail. But imagine if you replacedecho bios
with something that had other effects! Even when there's no risk, it's poorly self documenting, asa && b || c
doesn't achieve ternary conditional semantics outside such corner cases. – Eliah Kagan Apr 20 '18 at 20:39 -
Please suggest a better syntax to determine if the computer was booted in UEFI or BIOS mode. (I think a one-liner is best, it can be more complicated, since it can be copied and pasted.) – sudodus Apr 21 '18 at 05:35
-
1@sudodus Just based on the command you showed,
ls -ld /sys/firmware/efi
is more compact and clear about what it's doing; to say how to interpret its output is to explain how the test works. However, if your specific goal is to printefi
when the system is booted in UEFI mode andbios
when it's booted in BIOS mode, and you need to do it in a one-liner, then I would still preferif [ -d /sys/firmware/efi ]; then echo efi; else echo bios; fi
. It's longer, but it still fits comfortably on one line, and its meaning is extremely clear. Readers needn't consider the exit status ofecho efi
. – Eliah Kagan Apr 21 '18 at 11:06 -
I will follow your advice, but I think
test something
is easier to understand than[ something ]
so I would preferif test -d /sys/firmware/efi; then echo efi; else echo bios; fi
– sudodus Apr 21 '18 at 15:42 -
1@sudodus and EliahKagan
a && { b ; : ;} || c
provides a possible workaround for the problem: the group always returns0
no matter whetherb
failed. How abouttest -d /sys/firmware/efi && { echo efi; : ;} || echo bios
? – dessert Apr 23 '18 at 07:02 -
1@dessert, Yes it works too :-) But we must agree with EliahKagan that an 'if then else fi' statement is easier to understand than the logic behind '&& and ||'. – sudodus Apr 23 '18 at 07:07
&&
if you want a command to be executed conditionally based on the exit status of the previous one – steeldriver Apr 20 '18 at 19:13