9

My search this morning was about how could I compare two decimal numbers in bash, and I came to this answser: How to compare to floating point number in a shell script. This one, however, doesn't include this answer here:

$ [[ ((3.56 < 2.90)) ]]; echo $?
1
$ [[ ((3.56 < 4.90)) ]]; echo $?
0

Considering that answer has been downvoted, and it looks some kind of unusual bashism, is this arithmetic evaluation trustworthy for accuracy?

0

2 Answers 2

13

bash does not understand floating point numbers.
Quoting bash manual page, section ARITHMETIC EVALUATION:

Evaluation is done in fixed-width integers […].

So ((3 < 4)) or ((3 < 2)) are actually correct arithmetic expressions. You can type the following:

$ echo "$((3 < 4)) -- $((3 < 2))"

output: 1 -- 0

But $ echo $((3.3 < 3.6)) will return a syntax error message. In your example, you are actually comparing strings. Hence some example:

$ [[ ((3.56 < 04.90)) ]]; echo $?

output: 1

1
  • Both answers are awesome, but I'm choosing yours because of the example, which made me realize what could go wrong :) Jun 15, 2014 at 4:16
13

Inside [[...]] < is for string comparison.

So [[ 3.56 < 2.90 ]] or [[ (3.56 < 2.90) ]] or [[ ((3.56 < 2.90)) ]] or [[ (((3.56 < 2.90))) ]]... is just comparing the 3.56 string with the 2.90 string lexically (and lexically, 3 is greater than 10 for instance).

For integer comparison, it's [[ 3 -lt 2 ]] or (( 3 < 2 )). If you want floating point comparison, you need ksh93, zsh or yash or an external utility like awk or perl; bash can't do it.

You could for instance define a function like:

compare() (IFS=" "
  exec awk "BEGIN{if (!($*)) exit(1)}"
)

Which you could use for instance like:

if compare '1.5*10 < 1e3'; then
  echo less
fi

Or even for that matters:

if compare '"bar" < "foo"'...

to do string comparisons.

Do not pass uncontrolled externally provided data to that compare function as it would constitute a command injection vulnerability (the data is interpreted as awk code, awk can run commands with its system() for instance).

3
  • 2
    To illustrate the importance of the difference between string vs. numeric comparison, consider that [[ 11.56 < 2.90 ]] (and [[ ((11.56 < 2.90)) ]] and...) is true, because "1" comes before "2" in ascii sorting order. Jun 15, 2014 at 0:51
  • 1
    @GordonDavisson, yes, and [[ 0.1 < 1e-20 ]] and whether [[ -2 < 1 ]] is locale-dependent. Jun 15, 2014 at 9:31
  • [[ 3 -lt 2 ]] uses conditional expression, and (( 3 < 2 )) uses arithmetic expression. When comparing two integers, can these two methods always be used interchangeably? If yes, why does Bash have two methods rather than one?
    – Tim
    Apr 23, 2016 at 21:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .