What will happen if I write a line in bash like
commandA && commandB ; commandC
If commandA
fails, will commandC
be executed?
Yes, and you can easily check it yourself:
$ non-existent-command && echo hi ; echo after semicolon
bash: non-existent-command: command not found
after semicolon
In man bash
it says:
Commands separated by a ; are executed sequentially; the shell waits for each command to terminate in turn.
per the bash man page
[L]ist operators, && and || have equal precedence, followed by ; and &, which have equal precedence.
In practice this boils down to who cares about the return result. If the result is need right away it has higher precedence.
commandC
will be executed no matter if commandA
or commandB
fails or succeeds.
Semicolon is just a separator to make commands execute sequentially. The only scenario that I can see where commandC
will fail, is if commandA
or commandB
are exit
commands (or any command like return
/break
/continue
/exec
(or functions that call those) that forcefully affects the work flow):
Scenario 1: commandA
is exit
[root@host ~]# exit && echo "HI"; echo "test"
logout
[user@host ~]$
Scenario 2: commandB
is exit
[root@host~]# echo "HI" && exit; echo "test"
HI
logout
[user@host ~]$
tl;dr: Is not that those characters have a precedence. They mean different things. One is a logical operator and the other is a list terminator.
Related Stuff:
What are the shell's control and redirection operators? This answer gives a good explanation about the bash operators. Quoting a little piece of the answer:
;
: Will run one command after another has finished, irrespective of the outcome of the first.command1 ; command2
First
command1
is run, in the foreground, and once it has finished,command2
will be run.A newline that isn't in a string literal or after certain keywords is not equivalent to the semicolon operator. A list of
;
delimited simple commands is still a list - as in the shell's parser must still continue to read in the simple commands that follow a;
delimited simple command before executing, whereas a newline can delimit an entire command list - or list of lists. The difference is subtle, but complicated: given the shell has no previous imperative for reading in data following a newline, the newline marks a point where the shell can begin to evaluate the simple commands it has already read in, whereas a;
semi-colon does not.
Semicolons superfluous at the end of a line in shell scripts? Quoting the answer:
Single semicolons at the end of a line are superfluous, since the newline is also a command separator.
case
specifically needs double semicolons at the end of the last command in each pattern block; seehelp case
for details.
What's the difference between semicolon and double ampersand &&
&&
(and ||
) have a higher precedence than ;
(and |
). What do you mean, “One is for comparison and the other is to delimit where the next command on a list of commands will start (control operator).”? They are all control operators; they all delimit simple commands.
Commented
Jun 14, 2017 at 2:52
;
will execute no matter the outcome of what there is at left. It's a separator like newline
on shell scripts, and its reading is somehow like natural reading: first command line sequence ;
second command line sequence ;
third command line sequenc ;
etc
As other posts have said, the short answer is
“Yes, commandC
will be executed regardless of what else happens.”
As nwildner explored, the longer answer is,
“Yes, commandC
will be executed regardless of what else happens,
as long as the shell is still in a condition
in which it can execute commandC
.
In other words, the shell will not proceed beyond the
commandA && commandB ; command
command line without executing commandC
.”
Trivially, if commandA
(or commandB
) is kill -KILL $$
or something else that terminates or cripples the shell,
or disrupts the command flow, then commandC
will not be executed.
(Clearly we’re talking about edge cases here.)
Behavior is a little different if set -e
(or, equivalently, set -o errexit
) has been issued:
commandA
fails, commandC
will be executed
(but commandB
will not be).commandA
succeeds, then commandB
will be executed.
commandB
succeeds, then commandC
will be executed.commandB
fails, the shell will exit,
and commandC
will not be executed.The errexit
option specifies that the shell shall exit
if any command (any “pipeline”) fails, with some exceptions:
The shell does not exit if the command that fails is part of the command list immediately following a
while
oruntil
keyword, part of the test following theif
orelif
reserved words, part of any command executed in a&&
or||
list except the command following the final&&
or||
, any command in a pipeline but the last, or if the command's return value is being inverted with!
.— from bash(1)
So, if commandA
fails, that just causes commandB
not to be executed,
because commandA
is followed by &&
.
But if commandB
runs and fails, it causes the shell to exit,
because it (commandB
) follows the (final) &&
.
commandB
andcommandC
(ifcommandA
went OK), just writecommandA && (commandB ; commandC )