7

This question has two parts:

(a) Understanding what the code snipped is doing

(b) Understanding the difference between exit status and return status in context of bash.

Here is the code snipped I am trying to understand:

if var=-2 && (( var+=2 ))
then
    echo "True"
else
    echo "False"
fi

Running this produces False. I cannot understand why this is happening.

If I understand this correctly here is what maybe happening with the if condition:

(a) var=-2 creates exit status of 0, because the assignment is a success

(b) (( var+=2 )) adds 2 to the value of var and the expression evaluates zero. So the exit status is 1 for this term

(c) 0 && 1 creates an exist status of 0 which is then used by if construct

The if construct is supposed to simply check the exit status and when it is zero it takes the then path. In step (c) above it is zero but the script still takes the else path. Is this correct way to understand this?

Also, I keep seeing various bash texts use exit status and return status interchangeably.

I doubt var=-2 assignment would have any kind of exit status because it is not a program. But any clarification on the difference between two will be great.

  • 1
    run it with #!/bin/bash -x to see what it is happening – Rui F Ribeiro May 22 '17 at 10:33
  • 1
    + var=-2 + (( var+= 2 )) + echo 'False path is evaluated' This does not help me understand the exit status/return status being seen by the if construct. The point is understanding the construct, not to be cryptic. – sshekhar1980 May 22 '17 at 10:35
  • from man bash: expression1 && expression2 True if both expression1 and expression2 are true. expression1 || expression2 True if either expression1 or expression2 is true. The && and || operators do not evaluate expression2 if the value of expression1 is sufficient to determine the return value of the entire conditional expression. – MiniMax May 22 '17 at 16:46
  • 1
    Your misunderstanding seems to be in (c), specifically "0 && 1 creates an exist status of 0." 0 && 1, in fact, is 1. – Kevin May 22 '17 at 16:48
  • This is for the exact same reason i=0; ((i++)) has a failed exit status, whereas i=0; ((++i)) has a successful one. Inside an arithmetic context, positive integers are truthy and zero is falsey. – Charles Duffy May 22 '17 at 19:34
10

That's:

if
  first list of commands
then
  second list of commands
else
  third list of commands
fi

That's to run the second list of commands if the first list of commands returns with a true/success (zero) exit status, that is if the last run command in there returns with a zero exit status.

In:

var=-2 && ((var += 2))

It's cmd1 && cmd2 where cmd2 is only run if cmd1 is successful.

var=-2

Will typically be successful as long as $var has not been made read-only, so the ((var += 2)) command will be run:

((arithmetic expression))

Returns success/true as long as the expression is correctly evaluated (no syntax error) and the result of the expression is non-zero.

  • ((123)), ((1 + 1)), ((1 == 1)) return true
  • ((0)), ((-2 + 2)), ((2 == -2)) return false.
  • ((4294967296 * 4294967296)) return false in most shells because of 64 bit integer wrapping

var += 2 as an arithmetic expression, performs the assignment and resolves to the value being assigned, here 0, hence the false exit status.

You can see the value upon which is based the exit status, by using the $((...)) arithmetic expansion syntax:

$ echo "$((1 + 1)) $((2 == 2)) $((2 == -2)) $((var = -2)) $((var += 2))"
2 1 0 -2 0

Or assigning it to a variable:

$ var=-2; ((result = (var += 2)))
$ echo "$? $result $var"
1 0 0

$? contains the exit status of the previous command. As far as if/then/else/fi is concerned, 0 means true, anything else means false.

The confusion here comes from the fact that for arithmetic expressions, it's the other way round: 0 means false and anything else means true (for instance, 2 == 2 is 1 while 2 < 1 is 0).

To avoid worrying about the difference, just forget about $? and its possible values. Just think in terms of boolean true/false, sucess/failure.

 grep -q foo file

Returns true if foo is found in file.

 [ "$a" = "$b" ]

Returns true if $a contains the same thing as $b.

 ((6 * 3 - 12))
 ((4 == 1))

Return true if the result of the arithmetic expression is a non-zero number.

It doesn't matter whether those true/false are expressed in terms of 0 or 1 of the exit status of those grep/[ commands or ((...)) construct.

  • You are mistaken here: "The confusion here comes from the fact that for arithmetic expressions, it's the other way round: 0 means false and anything else means true (for instance, 2 == 2 is 1 while 2 > 1 is 0)." I have run this examples and got: ((2==2)); echo $? output 0 ((2 > 1)); echo $? output 0 – MiniMax May 22 '17 at 16:30
  • @MiniMax, you're missing my point. The 2==2 arithmetic expression results in 1 (see echo "$((2==2))"), because it's not 0, the ((...)) construct returns true (it returns a 0 exit status, but as I said you generally don't need to worry about which exit code means true or false) – Stéphane Chazelas May 22 '17 at 18:26
  • Now I understand your point. But why 2 > 1 is false, anyway? $((2 > 1)) is return 0, yes, therefore is false according your logic. In here "0 means false and anything else means true (for instance, 2 == 2 is 1 while 2 > 1 is 0)". I can't understand this sentence. – MiniMax May 22 '17 at 19:06
  • Wow, $((2 > 1)) results 1. :) Checked it now. – MiniMax May 22 '17 at 19:09
  • @MiniMax sorry that was a typo. Fixed now. – Stéphane Chazelas May 22 '17 at 21:59
3

(c) 0 && 1 creates an exist status of 0 which is then used by if construct

There's the mistake. 0 && 1 results in 1. This isn't C or Java, remember. In the shell 0 && 1 is what you'd get from true && false.

$ true; echo $?
0
$ false; echo $?
1
$ true && false; echo $?
1

Also, I keep seeing various bash texts use exit status and return status interchangeably.

They are interchangeable. What you want to keep in mind is that 0 indicates success and non-0 indicates failure. It's the opposite of most programming languages where 0 is false and 1 is true.

  • Good answer insofar as it goes, but the distinction between arithmetic value and exit status is important and doesn't appear to be explicitly defined. I'm not sure that the OP understands why an arithmetic operation with a result of 0 is different from a command with an exit status of 0. – Charles Duffy May 22 '17 at 19:36
0

Everything is working as expected .

if var=-2 && (( var+=2 ))
then
    echo "True"
else
    echo "False"
fi

Code explaination :-

if var=-2 && (( var+=2 ))

var=-2 => true Value is non-zero so evaluated as true

var+=2 => false Value is zero so evaluated as false

this is like

if true && false

As per logical computation true && false => false

In that case here is our final code

if (false)
then
    echo "True"
else
    echo "False"
fi
  • 3
    var=0, var=-2 evaluate to true. The value of the assigment doesn't matter here. var=1$(false) would return false. ((var=0)) would return false, ((var=1$(false))) would return true. – Stéphane Chazelas May 22 '17 at 11:36

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.