Register
It is currently Fri Oct 31, 2014 3:30 pm

Need help- Comparing version numbers


All times are UTC - 6 hours


Post new topic Reply to topic  [ 18 posts ] 
Author Message
 PostPosted: Thu Nov 18, 2010 9:14 am   

Joined: Thu Nov 18, 2010 8:55 am
Posts: 5
Hello,

I am a complete newbie to shell scripting. All my exposure has been to the windows platforms all these years.
I have just started working on shell scripts.

I have a problem wherein i need to compare two version numbers.
The version numbers have the format: <major>.<minor>.<build>.<revision>.
So essentially what this means is that: 1.01.02.03 is the same as 1.1.2.3.

I do not see a direct way to compare version numbers in shell scripting. All of the functions provided such as expr, bc etc do not handle cases which involves comparing version numbers such as 1.01.02.03 & 1.1.2.3.

Could anyone please guide me as to how i could achieve fool proof version number comparison in shell scripting?
If anyone could provide me with the piece of script, it would be great.


Second question:
How do i convert strings to numbers in shell scripting?

I am running short of time. Any help would be very much appreciated.

Regards,
Kiran Hegde


Top
 Profile  
 PostPosted: Thu Nov 18, 2010 2:41 pm   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
As long as all your versions contain exactly four numbers, this should work.
Code:
#!/bin/bash

function version { echo "$@" | awk -F. '{ printf("%d.%d.%d.%d\n", $1,$2,$3,$4); }'; }

if [ $(version 1.1.2.3) = $(version 1.01.02.00003) ]; then
  echo "equal"
else
  echo "not equal"
fi


Top
 Profile  
 PostPosted: Thu Nov 18, 2010 10:38 pm   

Joined: Thu Nov 18, 2010 8:55 am
Posts: 5
Hello,

Thanks for the quick response. My versions are not always intended to contain 4 numbers. I would have to zero pad them.
Let me try this and let you know if it meets my expectations.

Thanks again
Kiran Hegde


Top
 Profile  
 PostPosted: Fri Nov 19, 2010 5:19 am   

Joined: Thu Nov 18, 2010 8:55 am
Posts: 5
Hello,

I tried the following and it did **not** work


#!/bin/sh
function version { echo "$@" | awk -F. '{ printf("%d.%d.%d.%d\n", $1,$2,$3,$4);
}'; }

if [ $(version 1.11.2.301) < $(version 1.011.02.000030) ]; then
echo "equal"
else
echo "not equal"
fi

Any ideas why?

Regards,
Kiran Hegde


Top
 Profile  
 PostPosted: Fri Nov 19, 2010 2:05 pm   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
What you're doing there is wrong in a number of ways.
First: You're using a '<' which in shell script means: input redirection. If you want to use 'less than' in a test statement, use '-lt'
b) You're comparing 2 strings as though they were numbers
#3. In your OP you did not specify in what way you wanted to compare the version numbers. So I took the easy way and wrote a (not)equals comparison. If you want a 'less than'/'greater than' comparison you should have specified...


Top
 Profile  
 PostPosted: Sun Nov 21, 2010 1:24 am   

Joined: Thu Nov 18, 2010 8:55 am
Posts: 5
One question though: Why was = used instead of lt in your first response?
And also, isnt it the case that strings which contain numbers are treated as numbers in bash?

I am a complete newbie . So please excuse my ignorance

Do you know of any good links to get started with shell scripting


Top
 Profile  
 PostPosted: Sun Nov 21, 2010 2:58 am   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
The '=' was used to compare if the 2 version strings were equal. I didn't use '-lt' because that's an operator for numbers only and means 'less than'.
Variables containing only numbers can be treated as numbers in tests. The versions strings here do not only contain numbers, but also periods. Therefor they are strings.
The best way to start learning shell script, is to actually do shell script. Solve a problem in your head or on paper and try to implement it in code. If you get stuck forums like these are a good playground to see if somebody has a solution for your impediment. Most programming forums are not there to solve the problem itself, only to solve programming issues.


Top
 Profile  
 PostPosted: Mon Nov 22, 2010 8:13 am   
User avatar

Joined: Tue Apr 27, 2010 2:28 pm
Posts: 172
Location: Czech Republic
You can split your version strings into components and compare those. Something like this:
Code:
eval major=${version/./ minor=}
eval minor=${minor/./ build=}
eval build=${build/./ revision=}
if (( major < major2 )) ; then
...
fi

But be careful with leading zeros:
Code:
((012 < 11 )) && echo less

returns "less", because 012 is treated as octal, i.e. 10 in decimal!


Top
 Profile  
 PostPosted: Mon Nov 22, 2010 1:52 pm   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
I'd rather go for something like this:
Code:
#!/bin/sh

function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }

if [ $(version 10.1.2.4) -gt $(version 10.01.02.003) ]; then
  echo "$ver1 is newer $ver2"
else
  echo "$ver1 is NOT newer $ver2"
fi

It's not perfect either, don't get me wrong :)


Top
 Profile  
 PostPosted: Mon Nov 22, 2010 6:37 pm   
User avatar

Joined: Tue Apr 27, 2010 2:28 pm
Posts: 172
Location: Czech Republic
Patsie wrote:
It's not perfect either, don't get me wrong :)

Yes, it still takes 012 to be octal 10.


Top
 Profile  
 PostPosted: Mon Nov 22, 2010 11:30 pm   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
Ehm, no. That one is fixed by the awk. The first number is printed as %d which strips leading zeros.


Top
 Profile  
 PostPosted: Thu Nov 25, 2010 8:10 am   

Joined: Thu Nov 18, 2010 8:55 am
Posts: 5
I finally wrote a script to compare version numbers. Irrespective of how many significant digits are present in the version numbers, this works pretty well.
I used /bin/sh which defaults to Bourne shell and on some systems to bash.
Hence i could not use arrays.
Here is the code for the same:
#returns 0 for greater than
#returns 1 for less than
#returns 2 for equals
compare_ver_numbers()
{
#read the input parameters to the function
version1=$1
version2=$2
i=1


#zero pad the version strings
version1=`echo $version1 | awk -F"." '{printf("%d.%d.%d.%d",$1,$2,$3,$4); }'`
version2=`echo $version2 | awk -F"." '{printf("%d.%d.%d.%d",$1,$2,$3,$4); }'`

#Use a while loop to compare the individual elements of the array
#We are using bourne shell for compatibility across all flavours of unix.As a result of this, arrays are not supported in Bourne shell.
#Hence we have to resort to the method which has been used.


while [ $i -le 4 ]

do
if [ $i -eq 1 ]
then
val1=`echo $version1 | awk -F"." '{print $1}'`
val2=`echo $version2 | awk -F"." '{print $1}'`
fi

if [ $i -eq 2 ]
then
val1=`echo $version1 | awk -F"." '{print $2}'`
val2=`echo $version2 | awk -F"." '{print $2}'`
fi

if [ $i -eq 3 ]
then
val1=`echo $version1 | awk -F"." '{print $3}'`
val2=`echo $version2 | awk -F"." '{print $3}'`
fi

if [ $i -eq 4 ]
then
val1=`echo $version1 | awk -F"." '{print $4}'`
val2=`echo $version2 | awk -F"." '{print $4}'`
fi

if [ $val1 -gt $val2 ]
then
return 0
fi

if [ $val1 -lt $val2 ] ; then
return 1
fi
i=`expr $i + 1`


done

#If the control reaches here, it means both of the versions are equal
return 2


}

Is there a better way to do this? I had earlier used arrays. However arrays are not supported by Bourne shell. Hence i had to resort to the above method.Please let me know.

Regards,
Kiran Hegde


Top
 Profile  
 PostPosted: Fri Nov 26, 2010 3:42 pm   
User avatar

Joined: Tue Apr 27, 2010 2:28 pm
Posts: 172
Location: Czech Republic
Patsie wrote:
Ehm, no. That one is fixed by the awk. The first number is printed as %d which strips leading zeros.

I stand corrected. But it says
Code:
10.1.2.9 is NOT newer 10.01.02.008

Is it correct?


Top
 Profile  
 PostPosted: Fri Nov 26, 2010 4:35 pm   
Moderator
User avatar

Joined: Thu Oct 11, 2007 7:12 am
Posts: 229
Location: London - UK
Code:
[david@Galileo ~]# function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
[david@Galileo ~]# ver1=10.1.2.9
[david@Galileo ~]# ver2=10.01.02.008
[david@Galileo ~]# if [ $(version $ver1) -gt $(version $ver2) ]; then   echo "$ver1 is newer $ver2"; else   echo "$ver1 is NOT newer $ver2"; fi
10.1.2.9 is newer 10.01.02.008

^^ looks good to me


Top
 Profile  
 PostPosted: Sat Nov 27, 2010 2:02 am   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
Code:
$>cat ./test.sh
#!/bin/bash

ver1="10.1.2.9"
ver2="10.01.02.008"

function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }

if [ $(version $ver1) -gt $(version $ver2) ]; then
  echo "$ver1 is newer than $ver2"
else
  echo "$ver1 is NOT newer than $ver2"
fi

$>./test.sh
10.1.2.9 is newer than 10.01.02.008



Yeah, it looks fine here too...


Top
 Profile  
 PostPosted: Sat Nov 27, 2010 2:55 pm   
User avatar

Joined: Tue Apr 27, 2010 2:28 pm
Posts: 172
Location: Czech Republic
Stupid mistake on my side, I apologize.


Top
 Profile  
 PostPosted: Thu Feb 17, 2011 11:52 am   

Joined: Thu Feb 17, 2011 11:47 am
Posts: 1
I had the need to compare version numbers in a bash script, but wasn't satisfied with the existing answers, so poked around a bit. I found that the sort command has a --version-sort option that seems relatively smart about this, so I used it.


!/bin/bash

function vercomp {
[ ! $(echo -e "$1\n$2" | sort --version-sort | head -1) = "$2" ]
}

function test {
echo Testing that $1 \< $2
vercomp $1 $2 || echo "FAIL"
vercomp $2 $1 && echo "FAIL reversed"
vercomp $1 $1 && echo "FAIL $1 < $1"
vercomp $2 $2 && echo "FAIL $2 < $2"
}

test 1.0 1.1
test 1 1.000000001
test 1 2
test 1.1.1.1.1.2 1.1.1.1.1.3
test 1.1.1.1 1.01.001.0001.00001
test 10.01.02.008 10.1.2.9
test 1.0 1.0a
test 1.0 1.0.a


Top
 Profile  
 PostPosted: Thu Feb 17, 2011 2:00 pm   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
ohw, that's a very nice feature indeed. I was not aware of it yet.
You live and learn :)


Top
 Profile  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 18 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  


BashScripts | Promote Your Page Too
Powered by phpBB © 2011 phpBB Group
© 2003 - 2011 USA LINUX USERS GROUP