0
echo 1 && false && echo 2 || echo 3
1
3

echo 2 || echo 3
2

In the above code why doesn't it print 2 in the first case? and why does it print 2 in the second case?

muru
  • 72,889
  • 3
    https://en.wikipedia.org/wiki/Short-circuit_evaluation – pfnuesel Aug 28 '21 at 06:28
  • 2
    Does @pfnuesel comment answer your question. If not, then edit the question to explain what you are expecting and why (If we know what your current mental model is, then it may be easier to help). If the link helped, then close, as it is a duplicate. – ctrl-alt-delor Aug 28 '21 at 08:49

3 Answers3

2

The more general question What are the shell's control and redirection operators? and its answers will probably answer your question, but I'll give you a couple of rules of thumb to go by.

  • If you have a long and/or list, then you may see each || as meaning "if the most recently executed section in this list failed, run the next section" (where "fail" means return a non-zero exit-status).

  • Using the same type of reasoning, you may say that && means "if the most recently executed section in this list succeeded, run the next section" (where "succeed" means return a zero exit-status).

The above describes what's usually called short-circuit evaluation.

Using your code as an example, and assuming that each echo would execute successfully if it gets a chance to execute at all (echo would fail if the standard output stream was closed):

echo 1 && false && echo 2 || echo 3

The first echo 1 succeeds, so false runs. false fails (by design), so echo 2 does not run. echo 3, on the other hand runs as the most recently executed section of the list (false) failed.

Looking at

echo 2 || echo 3

Here, echo 2 runs first, but echo 3 does not because the most recently executed section of the list did not fail.

Kusalananda
  • 333,661
1

The shell executes commands in an strict left to right order (for OR & AND lists).

In this command:

echo 1 && false && echo 2 || echo 3

The first command is echo 1. It is executed and the exit status becomes 0 (even if it already was 0 at the start) as the exit status of echo is always 0.

When the first && is found the exit status is 0 (from above) meaning that the execution was successful, then the && is accepted and the next command gets executed.

On execution of false, the exit status becomes 1 (failed).

On finding the next &&, the current exit status is 1, the && gets rejected and the next command (echo 2) doesn't get executed.

But the line still has more code, so the shell walks to the next item, a ||. Being the current exit status 1 at that point, the || gets accepted and the next command (echo 3) gets executed.

The command echo 2 || echo 3 is very easy to analize. The first command gets executed (always) to get an exit code. That exit code is 0, the next || gets rejected and echo 3 is not executed. Nothing else to process, end of line.

1

I have a short explanation of && and || at this answer: https://unix.stackexchange.com/a/31881/4506m but here's a more detailed explanation of your particular examples.

First, it's important to know that unix commands either succeed or fail regardless of what output they might or might not produce. More precisely, a command succeeds if it has an exit status of zero, and fails if it has a non-zero exit status, but thinking in terms of exit statuses is confusing.

Given that, you might want to think of

  • cmd1 && cmd2 && ... && cmdN as evaluating the commands left to right until one fails, and
  • cmd1 || cmd2 || ... && cmdN as evaluating the commands left to right until one succeeds.

So, let's start with your first example

echo 1 && false && echo 2 || echo 3

This is made a bit more confusing by combining && and || operations without parentheses which makes the intended grouping unclear. It turns out that && and || have equal precedence and group to the left, but mixed sequences like this are often confusing. The precise meaning of this expression is

( ( ( echo 1 && false ) && echo 2 ) || echo 3 )

All right, what happens here?

  • The shell starts to evaluate ( ... || echo 3 ), but to do that it must first evaluate the left hand command.

  • The shell starts to evaluate ( ... && echo 2 ), but to do that it must first evaluate the left hand command.

  • The shell starts to evaluate ( echo 1 && false ), but to do that it must first evaluate the left hand command.

  • The shell evaluates echo 1 which will always succeed, ie, exit with a status code of zero. The fact that echo 1 also happens to print something is of no concern to the && operator, but it explains the first line of your output, 1\n.

  • The left operand of the first ( echo 1 && false ) succeededed, so the shell proceeds to evaluate the right operand, false. This is the command that always fails, and so the && expression as a whole fails.

  • The left operand of ( ... && echo 2 ) has already failed, so the shell does not execute echo 2, and this expression itself fails.

  • The left operand of ( ... || echo 3 ) has failed, so the shell does execute echo 3. This command produces your second line of output, but more importantly for the || operator, echo always succeeds, so the entire sequence of && and || operators succeeds.

  • If, after running your command, you'd typed echo $?, you'd see a value of zero, indicating that the previous command succeeded.

Your second example can be evaluated by same process outlined above, but let's go through it in detail.

echo 2 || echo 3

This is much simpler than your first example. The shell goes through the following steps.

  • The shell starts to evaluate echo 2 || echo 3, but to do so it must first evaluate left hand side.

  • The shell evaluates echo 2. This prints your one output line, and succeeds.

  • The shell continues evaluating echo 2 || echo 3, except now since the left hand succeeded, the rules of || state that the right hand side is not evaluated at all (and hence you do not get another line of output). Because the left hand side succeeded, the entire || expression succeeds.

This is pretty detailed, but I hope it helps.

  • thanks a lot. The detailed explanation is very informative and cleared my doubt. once again thanks alot – Nagarjuna Sep 04 '21 at 14:42