Vic VKh
Vic VKh

Reputation: 311

Why does bash evaluate comparison of numbers lexicographically not numerically?

Could someone explain the following behavior of the "if" block of bash ?

I use the following simple code check if the first_value is less than the second_value

first_value=67
second_value=2

if [[  "${first_value}" < "${second_value}" ]];
then 
    echo "Yes"
else 
    echo "No"
fi

The issue is

If the second_value is 1,2,3,4,5,6,10,11,... the block will return "No"

But if the second_value is 7,8,9 the block will return "Yes" (must be "No")

The fix is to use "-lt" instead of "<" but I want to understand such behavior of the "if" block.

The bash version is "GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)"

The OS is "CentOS Linux release 7.5.1804 (Core)"

Upvotes: 3

Views: 124

Answers (2)

user1934428
user1934428

Reputation: 22227

As for your question: First, an if block does not return anything. It just executes one set of statements or another ones, which in your case write something to stdout.

Now to the explanation of the behaviour you have observed.

The < operator in a [[ ... ]] expression does lexicographic comparison. For instance in

[[ 67 < 7 ]]

"67" is lexically smaller than "7", and hence [[ .... ]] returns status code 0, which means that the if is executing the then part, which causes Yes to be printed.

Upvotes: 1

xenteros
xenteros

Reputation: 15842

The reason for this behavior is the fact, that the [[ "${first_value}" < "${second_value}" ]] is actually lexicographic comparison, because of [[ exp ]] brackets.

As the OP mentions in the question, the possible fix is to use -lt operator.

In bash, you can use arithmetic context:

if (( $first_value < $second_value ));
then 
    echo "Yes"
else 
    echo "No"
fi

or even simpler

if (( first_value < second_value ));
then 
    echo "Yes"
else 
    echo "No"
fi

Upvotes: 4

Related Questions