Reputation: 1488
I'm working through some basic exercises using Bash and I'm confused on the order of operations of &&
and ||
. Below are some reproducible examples.
# Example 1
true && false || echo pass
# pass
Since the first true
is executed, &&
passes on to false
and false
is executed (true && false
). ||
evaluates false
and since there's a false
on the left hand side, echo pass
gets executed (false || echo pass
). So far so good.
false && false || echo pass
# pass
Since the first expression is false
, &&
does not execute the second false
. However, echo pass
gets printed because the left hand side of false || echo pass
is false. All is good so far.
[[ 2 -gt 3 ]] && echo t || echo f
# f
2
is not greater than 3
, meaning that echo t
doesn't get executed. However, echo t || echo f
prints f
. Based on the previous two examples, echo t
should return a non-exit code and don't execute echo f
on the right hand side.
What am I missing?
Upvotes: 3
Views: 4625
Reputation: 2654
The '&&' and '||' operators do not always execute the second operand. The shell will not execute the second operand if the result of the whole expression.
When evaluating 'cmd1 && cmd2', if 'cmd1' fails, 'cmd2' is not executed and the result is a failure. Otherwise, the result is the result of executing 'cmd2'.
Similarly, when evaluating 'cmd1 || cmd2', if 'cmd1' succeeds, 'cmd2' is not executed and the result is success. Otherwise, the result is the result of executing 'cmd2'.
When multiple operations are chained together, start with the left most pair and evaluate them according to the above two rules. Then replace the left most pair with the result and repeat. For example:
To run multiple commands, but stop and return an error upon the first failure:
cmd1 && cmd2 && cmd3 || echo "Failed."
This is equivalent to
( ( cmd1 && cmd2 ) && cmd3 ) || echo "Failed."
If cmd1 fails, cmd2 is not executed the first pair of commands fails. Therefore cmd3 is not executed and the left hand side of the '||' operator is a failure. Which means the echo command has to be executed.
Alternatively, if cmd1, cmd2 and cmd3 all succeed, then the left hand side of the '||' operator is successful and so the echo command is not executed.
Upvotes: -1
Reputation: 141000
a && b || c
is equal to ( a && b ) || c
, ie. the left side is one big expression. &&
and ||
have equal precedence, they are executed from left to right.The last command executed in [[ 2 -gt 3 ]] && echo t
is [[ 2 -gt 3 ]]
and it returns nonzero. So the exit status of the whole [[ 2 -gt 3 ]] && echo t
expression is nonzero - the exit status of last command executed.
[[ 2 -gt 3 ]] && echo t || echo f
( [[ 2 -gt 3 ]] && echo t ) || echo f
( false && echo t ) || echo f
( false ) || echo f
echo f
[*] - The rule is for any command that is in a list of commands ( )
{ }
&&
||
and also in compound constructs while
if
case
etc. You can do funny stuff like if case "$line" in a) false; ;; esac; then echo "line is not a"; fi
. The exit status of case
is equal the exit status of the last command executed, which is false
in case line
matches a)
.
Upvotes: 6