Comparison of decimal numbers in bash
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).
Related videos on Youtube
Rizwan Khan
Updated on September 18, 2022Comments
-
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 almost 10 yearsTo 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 almost 10 yearsBoth answers are awesome, but I'm choosing yours because of the example, which made me realize what could go wrong :)
-
Stéphane Chazelas almost 10 years@GordonDavisson, yes, and
[[ 0.1 < 1e-20 ]]
and whether[[ -2 < 1 ]]
is locale-dependent. -
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?