3

I have a file file1 which looks as below and carries current version and expected version numbers:

CurrV:1.5.2
ExpecV:1.8.1

I want to write a bash script to compare these two values and if ExpecV>=CurrV then I should echo SUCCESS, otherwise I should echo FAILURE.

So far I have written this thing, but not sure how to proceed:

#!/bin/bash
 ## Code already written to fetch `ExpecV` and `CurrV` from `file1`
 echo $ExpecV | grep $CurrV > /dev/null
 if [ $? -eq 0 ]
    then
        echo SUCCESS
    else
        echo FAILURE
 fi
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
all_techie
  • 2,761
  • 2
  • 11
  • 19
  • I think the condition you want, based on the comments you've left on my answer, is "if `ExpecV > CurrV`, then print `FAILURE`, else `SUCCESS`". – Benjamin W. Jan 29 '18 at 02:52
  • Additional answers can be found here: https://stackoverflow.com/q/4023830/619961. Essentially, it's about comparing two version strings in bash. – ikaerom Dec 05 '22 at 18:32

4 Answers4

4

You can try

if [ $(echo "${CurrV}\n${ExpecV}"|sort|head -1) != "${CurrV}" ]; then ...
Walter A
  • 19,067
  • 2
  • 23
  • 43
  • 4
    Use `|sort -V|` instead of `|sort|` there for a real sort by natural version number semantics. And in my case, `echo` needs to be `echo -e` so that it expands the \n as a newline. – Jürgen Weigert Mar 14 '22 at 13:01
  • This worked perfect! Quick and easy to comprehend. – kyrlon Dec 10 '22 at 04:13
2

The question says that ExpecV>=CurrV should be treated as success, but that does not make much sense (current version older than the expected one probably breaks something) and in your comments to this answer you allude to the desired behaviour being the other way around, so that's what this answer does.

This requires GNU sort for its -V option (version sort):

if cmp -s <(cut -d: -f2 infile) <(cut -d: -f2 infile | sort -V); then
    echo 'FAILURE'
else
    echo 'SUCCESS'
fi

This requires that the line with CurrV is always the first line. It extracts the parts after the colon with cut and compares the unsorted (first process substitution <(...)) to the version-sorted output (the second process substitution).

If they are the same, i.e., the version on the second line is greater than or equal to the one on the first line, the exit status of cmp is successful and we print FAILURE; if they aren't the same, this means that the sort inverted the order and the expected version is less than the current version, so we print SUCCESS.

The -s flag is to suppress output of cmp ("silent"); we're only interested in the exit status.


If you have 1.5.2 and 1.8.1 already in separate variables CurrV and ExpecV, you can do something similar as follows:

CurrV='1.5.2'
ExpecV='1.8.1'
printf -v versions '%s\n%s' "$CurrV" "$ExpecV"
if [[ $versions = "$(sort -V <<< "$versions")" ]]; then
    echo 'FAILURE'
else
    echo 'SUCCESS'
fi

This stores the two variables into versions, separated by a newline, then compares the unsorted with the sorted sequence.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
  • I have already written code to fetch `ExpecV` and `CurrV` from `file1` – all_techie Jan 28 '18 at 22:04
  • @all_techie Yes, my solution works only if the input file contains exactly what you show in the question: two lines, the first showing the current version, the second line the expected version. It doesn't work to directly version-compare two strings. – Benjamin W. Jan 28 '18 at 22:06
  • @all_techie Process substitution makes the output of a command available as if it were a file. Your attempt tries to run the contents of your variables as commands. My solution replaces your complete attempt and operates on the input file you show. – Benjamin W. Jan 28 '18 at 22:15
  • @all_techie I've added a variant starting with two variables. – Benjamin W. Jan 28 '18 at 22:27
  • Thanks. As per the logic the script should output `FAILURE` because `Currv` is less than `ExpecV` But when I run the script it is giving `SUCCESS` – all_techie Jan 28 '18 at 22:38
  • @all_techie The question reads "if ExpecV>=CurrV then I should echo SUCCESS". – Benjamin W. Jan 28 '18 at 22:42
  • This solution doesn't work if ExpecV==CurrV and you want SUCCESS – Geob-o-matic Jul 16 '21 at 09:40
1

Both the answers of @benjamin-w and @Walter A are very concise. We can also compare sub-version by sub-version numerical values using a for loop as this:

#!/bin/bash
#
# given 2 version numbers:
# check if ExpecV>=CurrV: SUCCESS
#
CurrV=1.5.2
ExpecV=1.8.1

#
# here below:
#   xarr: array of split CurrV numerical elements
#   yarr: array of split ExpecV numerical elements
#   isnewer: key if version ExpecV is newer than or equal to CurrV
#
#
# use parameter expansion to replace dot by space,
# and then convert them to arrays:
#
xarr=(${CurrV//./ })
yarr=(${ExpecV//./ })
    
#
# suppose that ExpecV is newer (bigger) or equal to CurrV version:
#
isnewer=true

#
# loop over array keys:
#
for i in "${!xarr[@]}"; do
  #
  #printf '${xarr[%s]}=%s\n' $i ${xarr[i]}
  #printf '${yarr[%s]}=%s\n' $i ${yarr[i]}
  #
  #
  # compare sub-version values: break if not equal:
  #
  if [ ${yarr[i]} -gt ${xarr[i]} ]; then
    break
  elif [ ${yarr[i]} -lt ${xarr[i]} ]; then
    isnewer=false
    break
  fi
done

#
# show result:
#
if [ $isnewer == true ]; then
  echo "SUCCESS: $ExpecV is newer than or equal to $CurrV."
else
  echo "FAILURE: $ExpecV is not newer than or equal to $CurrV."
fi
jacouh
  • 8,473
  • 5
  • 32
  • 43
1

If you are on a Debian system, then using dpkg is the easiest:

if dpkg --compare-versions $A lt $B
then
  # $A < $B was true
fi

It supports all six comparison operators (see man dpkg and search on compare-versions).

One potential drawback: your versions have to be Debian compatible.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156