2

I'm trying to compare version numbers. For example, if 10.9 is less than 10.11.

Can someone please explain why this doesn't print 'yes'?

 if [[ "9" < "10" ]]; then echo yes; fi

What do I need to do to make this work correctly as clearly, 9 should be less than 10?

In addition, if I have "10.9" in a variable $VERSION, how would this be compared with "10.11", as this also fails to print 'yes'

if [[ $VERSION < "10.11" ]]; then echo yes; fi
TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85

2 Answers2

2

In this case, this will return the correct answer

if [[ "8" < "9" ]]; then echo yes; fi

But for your specific case "10" is less than "9" because 1 is less than 9. String comparison works different than numeric, so the order will be something like that

1

10

20

21

3

...

You can convert your string to numeric and use the -lt (less than) operator for numeric values. Bash values are untyped so, this will work

if [ "9" -lt "10" ]; then echo yes; fi

Some Bash reference can be found here

Be aware that "10.9" lt isn't working with a float. You can use an awk comparison for this.

if [ -n "10.1" -a -n "10.2" ]; then echo yes; fi
Vargan
  • 1,277
  • 1
  • 11
  • 35
  • Sorry, my mistake. Having played around trying to get it to work, I missed the quotes. This is string comparison, so -lt doesn't work. – TheDarkKnight Jul 20 '15 at 09:47
  • Thanks, that makes sense, though I receive a version number as a string variable, how would I convert that to a numeric. As mentioned in my question, the version is "10.9" compared with "10.11". – TheDarkKnight Jul 20 '15 at 09:55
  • Simply use -lt :) answer edited – Vargan Jul 20 '15 at 10:06
  • That's fine to say with integers, but doesn't work with floats. Where $VERSION is a string, this fails: **if [[ $VERSION -lt 10.11 ]]; then echo yes; fi** – TheDarkKnight Jul 20 '15 at 10:09
  • This is because you have a dot. In comparison you have to use a comma. Dot is a meta character – Vargan Jul 20 '15 at 10:13
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/83732/discussion-between-vargan-and-thedarkknight). – Vargan Jul 20 '15 at 11:12
  • The dot is only a special character in a regular expression (the right-hand operand to the `=~` operator). Here, it's just another character in a string. – chepner Jul 20 '15 at 15:34
  • You're right chepner, modifying my answer – Vargan Jul 20 '15 at 16:32
1

Since < is a string comparison operator, "9" is lexicographically greater than "10". bash can only compare integers (using -lt, in which case [ "9" -lt "10 ] would be true. (Note that bash does not have separate string and integer types, only strings, meaning "9" and 9 are the exact same string. It's the operator, not the operands, that determine the behavior.)

bash does not work with floating point values at all. You need to use an external command (such as bc or awk) to compare them. Of course, if your version numbers can contain more than 1 decimal point, then you'll need to use some other approach, since they are no longer floating point numbers.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • I was a bit premature in thinking this works. When $VERSION is 10.9 or 10.12, they both output 'yes'. – TheDarkKnight Jul 20 '15 at 16:10
  • I overlooked how `bc` works. It outputs a 1=true, 0=false string; the exit status is independent of the result of the comparison. – chepner Jul 20 '15 at 16:16
  • Comparing **bc <<< "10.9 < 10.11"** with **bc <<< "10.12 < 10.11"**, they both return 0 – TheDarkKnight Jul 20 '15 at 16:26
  • Ugh. I don't use `bc` often; this might be the POSIX behavior I mentioned. In any case, the point is you need to use *some* other program (`awk` is another option). If your version numbers have more than one decimal point, then what you use to compare floating point values is a moot point, of course. – chepner Jul 20 '15 at 16:58