47

Why does bash have the following behavior?

echo $((true == false))
1

I would have thought that this would print 0, but it prints 1.

This is further complicated by the following facts:

> echo $((true))
0
> echo $((false))
0
> echo $((true == true))
1
> echo $((false == false))
1
HaskellElephant
  • 9,819
  • 4
  • 38
  • 67

2 Answers2

57

All the posters talking about 0 being true and 1 being false have missed the point. In this case, 1 is true and 0 is false in the usual boolean sense because of the arithmetic evaluation context caused by $(()).

The == operation inside of $(()) is not equality of return statuses in Bash, it performs numeric equality using the literals given where "false" and "true" are treated as variable, but have not yet been bound, which both are interpreted as 0 since they have no value yet assigned:

$ echo $((true))
0
$ echo $((false))
0

If you want to compare the return status of true and false you want something like:

true
TRUE=$?
false
FALSE=$?
if (( $TRUE == $FALSE )); then echo TRUE; else echo FALSE; fi

But, I'm not sure why you would want to do this.

EDIT: Corrected the part in the original answer about "true" and "false" being interpreted as strings. They are not. They are treated as variables, but have no value bound to them yet.

zostay
  • 3,985
  • 21
  • 30
  • Also, `echo $(( $TRUE == $FALSE ))` will report `0` as you would expect. `echo $(( $TRUE == $TRUE ))` and `echo $(( $FALSE == $FALSE ))` will also report `1`. – zostay Dec 20 '11 at 17:44
  • This is correct. "true" and "false" as booleans do not exist in bash and thus don't have a special meaning inside `$(())` – sorpigal Dec 20 '11 at 18:56
  • 2
    +1, and -1 to all the other answers... did anyone else even read the question? – Random832 Dec 20 '11 at 19:01
  • I'm sorry, but this does not hold. For one: if `(( $TRUE == $FALSE )); then echo TRUE; else echo FALSE; fi` is a syntax error on `((`. And then `$((...))` performs arithmetic evaluation on its operands. The fact that `$((true))` returns 0 is because there is no variable in the environment named `true`, and the arithmetic evaluation of operands yields 0 for **ANY** string. – fge Dec 20 '11 at 21:51
  • @fge You are incorrect because you're misunderstanding variable insertion. Because `TRUE` and `FALSE` are not defined in your shell, that line evaluates to `if (( == ));....`, which _of course_ is a syntax error. To see the correct result, add `TRUE=1; FALSE=0` before trying that if statement. – Izkata Dec 20 '11 at 22:45
  • 1
    @fge, you are partially correct, but not totally. It is true that `$((true))` returns 0 because $true is not assigned a value in the local environment (which I did not get entirely correct in my explanation) and will correct momentarily. I believe @izkata has already explained the part where you are not completely correct, since `if (( $TRUE == $FALSE )); ...` as given ran just fine on Bash 3.2 on my Mac using a fresh environment. It may very well be a syntax error on an older version of Bash. – zostay Dec 21 '11 at 02:57
22

OK, so, it seems there is a lot of confusion about what $((...)) really does.

It does an arithmetic evaluation of its operands, barewords are variables, not commands or string literals (ie, true is really $true), and anything which is not a number is 0. The == operator compares two numbers, and returns 1 if they are equal.

Which is why $((true == false)) is 1: there is no true or false environment variables in the environment, which means both $true and $false evaluate to the empty string, therefore 0 in arithmetic context!

To be complete, you can also use command substitution in arithmetic context... For instance:

$ echo $((`echo 2`))
2
$ echo $((3 + $(echo 4)))
7
$ a=3
$ echo $((a + $(echo 4)))
7
# undefine a
$ a=
$ echo $((a + $(echo 4)))
4
$ a="Hello world"
$ echo $((a + 1))
1
# undefine a again
$ a=
$ echo $(($(echo $a)))
0
fge
  • 119,121
  • 33
  • 254
  • 329
  • I already upvoted this answer because you're correctly saying the exact same thing as @zostay, you just didn't understand his example. You're getting a syntax error because TRUE and FALSE were not defined in your shell; his full example DID define them as the numeric return codes of the true and false commands (Look more closely at the 4 lines above it in the other answer; `TRUE=$?` is defining the variable $TRUE, etc..) – Izkata Dec 20 '11 at 22:56
  • I stand corrected for the example. But no, I'm not saying the same thing: @zostay says that `true` and `false` are treated as strings -- _this is not the case_! They are treated as environment variables, which is a completely different beast, and `$true` and `$false` evaluate to empty strings, not literals. try `echo $(($(echo $a)))` where `a` is not defined: it doesn't yield a syntax error but returns 0. He rightly says, though, that strings evaluate to 0. But in fact, anything which is not a number evaluates to 0 in this context. – fge Dec 20 '11 at 23:04