Reputation: 354
# 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
Reputation: 18687
There's a fundamental difference between those two compound commands inside a conditional construct.
[[ expression ]]
compound commandIn 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 commandIn 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
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 ofexpression
. 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
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
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