7

What will happen if I write a line in bash like

commandA && commandB ; commandC

If commandA fails, will commandC be executed?

  • just in case you want both commandB and commandC (if commandA went OK), just write commandA && (commandB ; commandC ) – Archemar Jun 13 '17 at 14:28
10

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.

3

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; see help case for details.

  • What's the difference between semicolon and double ampersand &&

  • 1
    What do you mean, “Is not that those characters have a precedence.”? && (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. – G-Man Jun 14 '17 at 2:52
  • Fixed the confusion: One is a logical operator while the other is a list terminator both being control operators. But they dont have "precedence" at all, since ; 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 – user34720 Jun 14 '17 at 10:35
1

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.

1

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:

  • If commandA fails, commandC will be executed (but commandB will not be).
  • If commandA succeeds, then commandB will be executed.
    • If commandB succeeds, then commandC will be executed.
    • If 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 or until keyword, part of the test following the if or elif 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) &&.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.