Daniel E
Daniel E

Reputation: 354

Why does this if statement get evaluated to true in bash?

# prints "here" when run in bash
if [[ ((9 > 220)) ]]; then echo "here"; fi

I'm confused why the above if statement gets evaluated to true. Wouldn't ((9 > 220)) evaluate to false which would make the if statement false? The code below behaves as expected. I'm confused why using the double parentheses in a double brackets "if" isn't working above though.

# doesn't print anything
if ((9 > 220)); then echo "here"; fi

Upvotes: 1

Views: 199

Answers (4)

randomir
randomir

Reputation: 18687

There's a fundamental difference between those two compound commands inside a conditional construct.

[[ expression ]] compound command

In your first example you're using the [[ expression ]] command:

if [[ ((9 > 220)) ]]; then echo "here"; fi

where parenthesis are treated merely as grouping operators, used to override the normal precedence of other operators (like !, &&, ||, >, -gt, -e, etc.). The > operator in this case is a lexicographic greater than.

This is nicely described in man bash:

[[ expression ]]

Return a status of 0 or 1 depending on the evaluation of the conditional expression expression. Expressions are composed of the primaries described below under CONDITIONAL EXPRESSIONS. Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed. Conditional operators such as -f must be unquoted to be recognized as primaries.

When used with [[, the < and > operators sort lexicographically using the current locale.

So, to compare integers in the [[ compound command, you can use the conditional expression operators, the same one used by test and [ commands. For example like this:

if [[ 9 -gt 220 ]]; then echo "here"; fi

The result is the same like when the -gt operator is grouped with parenthesis:

if [[ ((9 -gt 220)) ]]; then echo "here"; fi

Alternatively, you can use the arithmetic expansion and exploit the fact that the boolean results are represented as "0" or "1":

if [[ $((9 > 200)) == 1 ]]; then echo "here"; fi

(( expression )) compound command

In your second example, you're using the (( expression )) command:

if ((9 > 220)); then echo "here"; fi

where the expression is evaluated according to the rules of the shell arithmetic. The man bash says:

((expression))

The expression is evaluated according to the rules described below under ARITHMETIC EVALUATION. If the value of the expression is non-zero, the return status is 0; otherwise the return status is 1. This is exactly equivalent to let "expression".

Upvotes: 1

Benjamin W.
Benjamin W.

Reputation: 52102

Inside of [[ ]], the parentheses don't trigger an arithmetic context, they're interpreted purely for grouping/precedence1. All of these are equivalent:

$ [[ 0 < 1 ]] && echo yes
yes
$ [[ (0 < 1) ]] && echo yes
yes
$ [[ ((0 < 1)) ]] && echo yes
yes
$ [[ (((0 < 1))) ]] && echo yes
yes
$ [[ ((((0 < 1)))) ]] && echo yes
yes

If we have unbalanced parentheses, Bash complains about that:

$ [[ ((((0 < 1))) ]] && echo yes
bash: unexpected token `]]', expected `)'
bash: syntax error near `]]'

This all being said, < and > within [[ ]] are for lexicographical string comparison, so the statement above just checks if 0 is lexicographically sorted before 1 (it is).

Observe:

$ [[ 11 < 2 ]] && echo yes
yes

To compare numbers, you have to use -gt, -lt, -ge, -le, eq, ne instead of >, <, >=, <=, =, !=:

$ [[ 11 -lt 2 ]] && echo yes || echo no
no

Since you're already using (( )), you could use just that for comparing numbers:

$ (( 11 < 2 )) && echo yes || echo no
no

This is the simplest and clearest method in my opinion, if you know you have Bash at your disposal.


1 See the manual about [[ ]]:

Expressions may be combined using the following operators, listed in decreasing order of precedence:

( expression )
Returns the value of expression. This may be used to override the normal precedence of operators.

Hat tip to glenn jackman for pointing to the manual in his comment to another answer.

Upvotes: 0

Cary Shindell
Cary Shindell

Reputation: 1386

It is because using double brackets makes it a lexicographical comparison. That means that it checks for which sequence is longer, like sorting alphabetically. More information about lexicographical comparisons here

Upvotes: 1

Elan Hamburger
Elan Hamburger

Reputation: 2177

The double parentheses is an arithmetic context. If you use the brackets, you have to use -lt for less than and -gt for greater than. See Comparing numbers in Bash.

Upvotes: -1

Related Questions