Comparison of decimal numbers in bash

19,249

Solution 1

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

Solution 2

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).

Share:
19,249

Related videos on Youtube

Rizwan Khan
Author by

Rizwan Khan

Updated on September 18, 2022

Comments

  • Rizwan Khan
    Rizwan Khan over 1 year

    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?

  • javaamtho
    javaamtho almost 10 years
    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.
  • Rizwan Khan
    Rizwan Khan almost 10 years
    Both answers are awesome, but I'm choosing yours because of the example, which made me realize what could go wrong :)
  • Stéphane Chazelas
    Stéphane Chazelas almost 10 years
    @GordonDavisson, yes, and [[ 0.1 < 1e-20 ]] and whether [[ -2 < 1 ]] is locale-dependent.
  • Tim
    Tim about 8 years
    [[ 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?