mar627
mar627

Reputation: 25

Why does command after `||` execute even if prior command succeeds?

I am using short-circuit evaluation (with && and ||) in a bash function, and I don't understand the behavior I'm seeing.  I want the function to return if the first number is not greater than the second:

[[ 5 > 2 ]] && echo true || echo false && return

#    ^             ^                   ^
# true so       do this        not this && this


[[ 5 > 8 ]] && echo true || echo false && return

#    ^             ^                   ^ 
# false so   don't do this      do this && this

but the function returns in either case.  Why does the return command execute regardless of the first command's status?

Instead of return I have tried break, but it doesn't work due to not being within a loop.

  1. Why does return seem to execute in both these cases?

  2. How else can I end a running function?

Upvotes: 1

Views: 89

Answers (2)

    stmt1  &&  stmt2    ||  stmt3    &&  stmt4

is evaluated as

( ( stmt1  &&  stmt2 )  ||  stmt3 )  &&  stmt4

i.e., left to right.

So the logic is

Execute stmt1
If it succeeds,
then
    execute stmt2
endif
If stmt1 succeeds and stmt2 succeeds,
then
    (do nothing here)
else                    # i.e., if stmt1 fails,  OR  stmt1 succeeds and then stmt2 fails
    execute stmt3
endif
If stmt1 succeeds and stmt2 succeeds,
                  OR  stmt3 succeeds,
then
    execute stmt4
endif

Since stmt2 and stmt3 are both echo statements, they both always succeed, and so stmt4 (the return statement) is always executed.

I suspect you were expecting

( stmt1  &&  stmt2 )  ||  ( stmt3  &&  stmt4 )

and you can get that behavior (in general) by typing parentheses, just like that:

 ( [[ 5 > N ]] && echo true )  ||  ( echo false && return )         # No, don’t do this

or braces:

{ [[ 5 > N ]] && echo true; }  ||  { echo false && return; }

Note that you must have whitespace after a { and a semicolon before a }.

Note also that, with parentheses, the commands run in subshells, whereas with braces, they don’t (they run in the main shell context).  In your specific code example, you must use braces (at least for the part after the ||), because return doesn’t have any effect if it’s run in a subshell.

Upvotes: 4

Barmar
Barmar

Reputation: 780974

Use if instead of logical operators.

if [[ 5 > 8 ]]
then echo true
else
    echo false
    return
fi

See precedence of the shell logical operators for an explanation of how the operators combine.

Upvotes: 2

Related Questions