5

Trying to write a script that searches for the version of the Application then returns the value. My problem is the value is three to four intergers long (example 4.3.2).

I have searched for a while and can't find any syntax that would allow you to use a != or -ge for anything higher than a number with periods in it. Just wondering if anyone has a better way or I will just keep adding for every version release.

What I want

else if [ $version1 -ge "9.0.8" ]; then

How it is written now

vercheck=`mdls -name kMDItemVersion /Applications/iMovie.app`
version=`echo ${vercheck:17}`
version1=`echo ${version:1:5}`

[...]

else if [ $version1 = "9.0.8" ]; [ $version1 = "9.1.1" ]; then
    echo "You already have this version or a higher version installed"
    exit 0
3
  • 2
    See stackoverflow.com/questions/4023830/…
    – Matteo
    Commented Mar 1, 2013 at 16:59
  • The solution Matteo linked to seems way more complicated than it needs to be, unless I'm misunderstanding something. I've posted a shorter solution below.
    – TJ Luoma
    Commented Mar 6, 2014 at 20:39
  • BTW mdls -raw -name kMDItemVersion /Applications/iMovie.app will give you just the version number without the superfluous stuff.
    – TJ Luoma
    Commented Mar 6, 2014 at 20:40

5 Answers 5

4

I believe I adapted this slightly from http://bashscripts.org/forum/viewtopic.php?f=16&t=1248. I like it because it's fairly compact and readable.

This is optional, but desirable IMO:

if [ "$#" != "2" ]
then
    echo "$0 requires exactly two arguments."
    exit 2
fi

Here's the meat:

I always use $1 for "the locally installed version" and $2 for "the version I am comparing against" so if this leaves me with $? = 1 I need to update, otherwise I'm up-to-date (or even ahead):

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

if [ $(version $1) -gt $(version $2) ]; then
    echo "$1 is newer than $2"
    exit 0
elif [ $(version $1) -lt $(version $2) ]; then
    echo "$1 is older than $2"
    exit 1
else
    echo "$1 is identical to $2"
    exit 0
fi

If all you cared about was whether $1 was up to date (that is, equal to or greater than $2) you could make it even simpler:

if [ $(version $1) -ge $(version $2) ]; then
    echo "No Newer Version Available"
    exit 0
fi

Any code below that will only be executed if there is a newer version available. Otherwise the script will exit cleanly at that point.

p.s.: I do this in /bin/zsh not /bin/bash but I don't think it makes a difference in this case.

0

Actually, comparing version numbers is pretty straightforward (at least as long as they are strictly numeric) as they are hierarchically structured left to right. A sequential comparison in that same order will yield a clear result.

The following bash function will return 0 (true) if two version numbers are not equal, 1 (false) if they are, as long as the variables $version_1 and $version_2 both contain only an arbitrary number of digit groups separated by periods:

function versions_not_equal {
    while [[ $version_1 != "0" || $version_2 != "0" ]]; do
        (( ${version_1%%.*} != ${version_2%%.*} )) && return 0
        [[ ${version_1} =~ "." ]] && version_1="${version_1#*.}" || version_1=0
        [[ ${version_2} =~ "." ]] && version_2="${version_2#*.}" || version_2=0
    done
    false
}

Implementing other comparisons, like greater or equal, is as simple as changing the comparison operator of the arithmetic evaluation (i.e. (( ${version_1%%.*} >= "${version_2%%.*}" ))).

0

I can give you a long example of "if the checked version is between min and max" and you can optimize it for your needs changing head -1/tail -1 and cutting 1 variable:

min_ver="a-1.1.1"
max_ver="a-9.1.1"
check_ver="a-2.2.9"
if [ "$( echo -e "${min_ver}\\n${max_ver}\\n${check_ver}" | sort --sort=version | head -2 | tail -1)" == ${check_ver} ]
then
  echo YES - apply  ${check_ver}
fi
0

Here's another solution that:

  • does not run any external command apart from tr
  • has no restriction on number of parts in version string
  • can compare version strings with different number of parts

Note that it's Bash code using array variables.

compare_versions()
{
    local v1=( $(echo "$1" | tr '.' ' ') )
    local v2=( $(echo "$2" | tr '.' ' ') )
    local len="$(max "${#v1[*]}" "${#v2[*]}")"
    for ((i=0; i<len; i++))
    do
        [ "${v1[i]:-0}" -gt "${v2[i]:-0}" ] && return 1
        [ "${v1[i]:-0}" -lt "${v2[i]:-0}" ] && return 2
    done
    return 0
}

The function returns:

  • 0 if versions are equal (btw: 1.2 == 1.2.0)
  • 1 if the 1st version is bigger / newer
  • 2 if the 2nd version is bigger / newer

However #1 -- it requires one additional function (but function min is quite usable to have anyway):

min()
{
    local m="$1"
    for n in "$@"
    do
        [ "$n" -lt "$m" ] && m="$n"
    done
    echo "$m"
}

However #2 -- it cannot compare version strings with alpha-numeric parts (though that would not be difficult to add, actually).

0

You can use version CLI to check version's constraints

$ version ">=1.0, <2.0" "1.7"
$ go version | version ">=1.9"

Bash script example:

#!/bin/bash

if `version -b ">=9.0.0" "$(gcc --version)"`; then
  echo "gcc version satisfies constraints >=9.0.0"
else
  echo "gcc version doesn't satisfies constraints >=9.0.0"
fi

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .