Page 1 of 1

How to compare versions in a Bash script? (Solved)

Posted: Mon 25 Aug 2014, 18:44
by linus.cl
Hello!

How can I compare two versions in my Bash script?

I have two versions:

Code: Select all

2.7.1-i486s 2.3-2-spup 
^new          ^old
They are saved in two variables: $newversion and $oldversion
I try to compare them.

I hope, you can help me... :D

Posted: Mon 25 Aug 2014, 19:53
by 6502coder
You mean that you just want to test two shell variables to see if they are the same string? That's easy:

Code: Select all

if [ $newversion  =  $oldversion ]
then
	echo same
else
	echo different
fi

Posted: Mon 25 Aug 2014, 19:57
by linus.cl
No, i'd like to check if $newversion is newer.

I found an application: vercmp.
https://www.archlinux.org/pacman/vercmp.8.html

But I can't use it. (I don't understand it)

Posted: Mon 25 Aug 2014, 22:29
by RSH

Code: Select all

if vercmp ${NEWVERSION} gt ${OLDVERSION} ; then 
	echo $NEWVERSION
fi

Posted: Tue 26 Aug 2014, 02:27
by MochiMoppel
linus.cl wrote:I found an application: vercmp.
No need for an application. Try this:

Code: Select all

newversion="2.7.1-i486s"
oldversion="2.3-2-spup"
[[ "$newversion" > "$oldversion" ]] && echo "newversion is newer" || echo "oldversion is newer"
The > operator compares 2 strings by their alphabetic ASCII order. Requires a double bracket test construct to work.

Posted: Tue 26 Aug 2014, 14:20
by gcmartin
Hello @Linus.cl

Noticing some of the very good things you are aiming into the community, you may find this tool to have "tremendous " advantage to your use and development efforts. Install and observe. It will meet much much more than you ask while accelerating your work efforts. And, there is no system penalty in its presence as a tool.

Here to help

Posted: Tue 26 Aug 2014, 14:39
by jamesbond
There are a few versions of "vercmp" floating around. Since you're building for Puppy, might as well use Puppy's own vercmp. It's here: https://github.com/puppylinux-woof-CE/w ... t/vercmp.c. If you google "barry kauler vercmp" you will find a few links.

Posted: Thu 28 Aug 2014, 02:16
by technosaurus
sort -V or sort --version-sort works too
use head -n1 or tail -n1 for the oldest/newest (works for comparing 2 or more)

Posted: Mon 15 Dec 2014, 18:11
by Karl Godt
I would use case for that

Code: Select all

case $BASH_VERSION in
1.*) : do_something;;
2.[0-2].*) : do_something_else;;
2.3.*) echo OLD VERSION;;
2.[4-6].*) : do_something_else_more;;
2.7.*) echo NEW VERSION;;
*) echo UNHANDLED bash version $BASH_VERSION;;
esac
5.2 Bash Variables

These variables are set or used by Bash, but other shells do not normally treat them specially.

BASH_VERSINFO

A readonly array variable (see Arrays) whose members hold version information for this instance of Bash. The values assigned to the array members are as follows:

BASH_VERSINFO[0]

The major version number (the release).
BASH_VERSINFO[1]

The minor version number (the version).
BASH_VERSINFO[2]

The patch level.
BASH_VERSINFO[3]

The build version.
BASH_VERSINFO[4]

The release status (e.g., beta1).
BASH_VERSINFO[5]

The value of MACHTYPE.

BASH_VERSION

The version number of the current instance of Bash.

http://www.gnu.org/software/bash/manual ... oking-Bash


Bash version 2.Y may not know some of these variables .

Posted: Thu 30 Apr 2020, 14:13
by goingnuts
From above inputs I put together below shell-version of vercmp which also works with ash/busybox only systems:

Code: Select all

#!/bin/sh
help () {
	echo "usage: vercmp-shell version1 lt|gt|le|ge|eq version2
       return value 0 if true, else 1"
}

[ $# -ne 3 ] && help && exit 2


case "$2" in
	lt)		[ "$1" != "$3" ] && [ "$(echo $1,$3 | tr ',' '\n' | sort -k1,1n | head -n1)" = "$1" ] && exit 0 || exit 1;;
	gt)	[ "$1" != "$3" ] && [ "$(echo $1,$3 | tr ',' '\n' | sort -k1,1n | tail -n1)" = "$1" ] && exit 0 || exit 1;;
	le)	[ "$1" = "$3" ] || [ "$(echo $1,$3 | tr ',' '\n' | sort -k1,1n | head -n1)" = "$1" ] && exit 0 || exit 1;;
	ge)	[ "$1" = "$3" ] || [ "$(echo $1,$3 | tr ',' '\n' | sort -k1,1n | tail -n1)" = "$1" ] && exit 0 || exit 1;;
	eq)	[ "$1" = "$3" ] && exit 0 || exit 1;;
	*) 	help && exit 1;;
esac

exit

Posted: Fri 01 May 2020, 02:42
by MochiMoppel
Nice. However unlike the binary vercmp it might give false results when the version string contains commas, e.g. "GNU bash, version 4.4.12(1)-release (i686-pc-linux-gnu)"

I think it would be better to change

Code: Select all

echo $1,$3 | tr ',' '\n' | sort -k1,1n
to something more robust like

Code: Select all

printf '%s\n%s' "$1" "$3" | sort -k1,1n
Would still work with ash

Posted: Fri 01 May 2020, 18:00
by goingnuts
Agree - thanks for improvement input! :D
Follow up 20200503: For robustness one could also change from:

Code: Select all

echo $1,$3 | tr ',' '\n' | sort -k1,1n
to:

Code: Select all

echo $1/$3 | tr '/' '\n' | sort -k1,1n
or to eliminate the use of tr one could change to:

Code: Select all

echo -e "$1\n$3" | sort -k1,1n
The printf is sure best way but not all systems has it - echo seems more likely to be everywhere...but might not always support -e though.