1

I'm trying to compare values of two variables both containing strings-as-numbers. For example:

var1="5.4.7.1"
var2="6.2.4.5"

var3="1-4"
var4="1-5"

var5="2.3-3"
var6="2.3.4"

Sadly, I don't even know where to start... Any help will be appreciated!

What I meant is how would I go about comparing the value of $var5 to $var6 and determine with one of them is higher.

EDIT: Better description of the problem.

  • See here: http://stackoverflow.com/questions/4023830/bash-how-compare-two-strings-in-version-format – anubhava Nov 15 '13 at 19:26
  • 1
    I'm not sure to understand exactly what is asked. Could you give us a complete example with the desired output? – Maxime Chéramy Nov 15 '13 at 19:32
  • Thanks! That will keep me busy for a while :-) – user2997549 Nov 15 '13 at 19:33
  • I'm not sure that this can be satisfactorily answered. Comparing, as you want, `var5` and `var6` would require some semantic knowledge of how these were generated and how they're used, because usage of those forms is not universally consistent. Some would see `2.3-3` as equivalent to `2.3.3` - the third (or fourth if zero-based) point release of major release 2 minor release 3. Others would see it as equivalent to `2.3.0-3` - the third or fourth rebuild/repackaging of major version 2 minor version 3. Comparing two variables using the same form (i.e. `var1` and `var2`) is less problematic. – twalberg Nov 15 '13 at 19:59

2 Answers2

0

It depends of the required portability of the solution. If you don't care about that and you use a deb based distribution, you can use the dpkg --compare-versions feature.

However, if you need to run your script on distros without dpkg I would use following approach.

The value you need to compare consist of first (the first element) and the rest (all others). The first is usually called the head and the rest - tail, but I deliberately use names first and rest, to not confuse with head(1) and tail(1) tools available on Unix systems.

In case first($var1) is not equal to first($var2) you just compares those firsts elements. If firsts are equal, just recursively run the compare function on rest($var1) and rest($var2). As a border case you need to decide what to do if values are like:

var1 = "2.3.4"
var2 = "2.3"

and in some step you will compare empty and non-empty first.

Hint for implementing first and rest functions:

foo="2.3-4.5"
echo ${foo%%[^0-9][0-9]*}
echo ${foo#[0-9]*[^0-9]}

If those are unclear to you, read man bash section titled Parameter Expansion. Searching the manual for ## string will show you the exact section immediately.

Also, make sure, you are comparing elements numerically not in lexical order. For example compare the result of following commands:

[[ 9 > 10 ]]; echo $?
[[ 9 -gt 10 ]]; echo $?
ArturFH
  • 1,697
  • 15
  • 28
0

You can use [[ ${str1} < ${str2} ]] style test. This should work:

function max()
{
    [[ "$1" < "$2" ]] && echo $2 || echo $1
}

max=$(max ${var5} ${var6})
echo "max=${max}."
cforbish
  • 8,567
  • 3
  • 28
  • 32