How to check and compare rpm version and release in Linux using bash script

Recently I came into a situation where I was supposed to install a hotfix patch on my Linux setup where I was supposed to programmatically compare the version of all the available rpms with the list of rpms downloaded from the yum repository. Now in most organization the linux servers would not be connected to internet hence the comparing part needs to be done manually.

Now I have an excel sheet which has 1000+ rpms and on my setup I have around 400+ rpms installed. Now I should compare rpms at both places and if any new rpm is found then update the same.

Comparing rpm versions is very tricky as each one has their own syntax and they do not follow a general syntax or naming convention other than the below format

name-release-version.arch

But here each section can be different.
With Red Hat we have a tool "rpmdev-vercmp" which is part of "yum-utils" rpm

This tool can be used to perform the comparison

# rpmdev-vercmp python-chardet-2.2.1-1.el7_1.noarch python-chardet-2.2.1-1.el7_2.noarch
python-chardet-2.2.1-1.el7_1.noarch < python-chardet-2.2.1-1.el7_2.noarch

But my fade of luck, I am not allowed to install this additional rpm. So I decided to write my own algorithm to compare rpm versions and I came up with below script

#!/bin/bash

# Get both the package detail and store them in their respective variable
pkg1="$1"
pkg2="$2"

# Check if rpm is installed
function check_rpm_status {
 rpm -q $1 | grep -v "not installed" >/dev/null 2>&1
 if [ $? == "0" ];then
    return 0
 else
    return 1
 fi
}

function get_rpm_version {
 python -c "print '-'.join('$1'.rsplit('-',2)[-2:])"
}

# Get the version and release detail of both the packages
if check_rpm_status $pkg1;then
    pkg1_ver=`rpm -q --queryformat "%{VERSION}-%{RELEASE}.%{ARCH}n" $pkg1`
else
    pkg1_ver=$(get_rpm_version $pkg1)
fi

if check_rpm_status $pkg2;then
    pkg2_ver=`rpm -q --queryformat "%{VERSION}-%{RELEASE}.%{ARCH}n" $pkg2`
else
    pkg2_ver=$(get_rpm_version $pkg2)
fi

# Modify the collected version and release detail to further compare them
pkg1_ver_modified=`echo $pkg1_ver | sed -E -e 's/.el[0-9]|.x86_64|.i[0-9]86|.noarch//g; s/-|_/./g; s/[a-z]//g'`
pkg2_ver_modified=`echo $pkg2_ver | sed -E -e 's/.el[0-9]|.x86_64|.i[0-9]86|.noarch//g; s/-|_/./g; s/[a-z]//g'`

# Store the version into array for comparison
IFS="." read -a pkg1_array <<< ${pkg1_ver_modified}
IFS="." read  -a pkg2_array<<< ${pkg2_ver_modified}

# Collect the result and store in these variables
both_are_equal=0
pkg1_is_greater=0
pkg2_is_greater=0

# Main
for ((i=0; i<${#pkg1_array[@]} || i<${#pkg2_array[@]}; i++)); do
  [[ ${pkg1_array[$i]} -eq ${pkg2_array[$i]} ]] && ((both_are_equal++))
  if [[ ${pkg1_array[$i]} -gt ${pkg2_array[$i]} ]];then
     ((pkg1_is_greater++))
     break
  fi
  [[ ${pkg1_array[$i]} -lt ${pkg2_array[$i]} ]] && ((pkg2_is_greater++))
done

if [[ ${#pkg2_array[@]} -eq ${#pkg1_array[@]} && ${#pkg1_array[@]} -eq $both_are_equal ]];then
   echo "$pkg1 is equal to $pkg2"
elif [[ $pkg1_is_greater -gt "0" && $pkg2_is_greater -eq "0" ]];then
   echo "$pkg1 > $pkg2"
else
   echo "$pkg1 < $pkg2"
fi

This script will work same as "rpmdev-vercmp" tool.

Syntax:

/tmp/compare-rpm.sh $pkg1 $pkg2

Below are some examples I tried for various types of rpms

# ./compare-rpm.sh libssh2-1.4.13-4.el7_1.20.x86_64 libssh2-1.4.13-13.el7_1.20.x86_64
libssh2-1.4.13-4.el7_1.20.x86_64 < libssh2-1.4.13-13.el7_1.20.x86_64

# ./compare-rpm.sh selinux-policy-targeted-3.13.1-166.el7.noarch selinux-policy-targeted-3.12.1-166.el7.noarch
selinux-policy-targeted-3.13.1-166.el7.noarch > selinux-policy-targeted-3.12.1-166.el7.noarch

# ./compare-rpm.sh plymouth-core-libs-0.8.9-0.28.20140113.el7.x86_64 plymouth-core-libs-0.8.10-0.28.20140114.el7.x86_64
plymouth-core-libs-0.8.9-0.28.20140113.el7.x86_64 < plymouth-core-libs-0.8.10-0.28.20140114.el7.x86_64

# ./compare-rpm.sh net-tools-2.0-0.22.20131004git.el7.x86_64 net-tools-2.0-0.22.20141004git.el7.x86_64
net-tools-2.0-0.22.20131004git.el7.x86_64 < net-tools-2.0-0.22.20141004git.el7.x86_64

# ./compare-rpm.sh Red_Hat_Enterprise_Linux-Release_Notes-7-en-US-7-2.el7.noarch Red_Hat_Enterprise_Linux-Release_Notes-7-en-US-7-3.el7.noarch
Red_Hat_Enterprise_Linux-Release_Notes-7-en-US-7-2.el7.noarch < Red_Hat_Enterprise_Linux-Release_Notes-7-en-US-7-3.el7.noarch

# ./compare-rpm.sh  linux-firmware-20170606-56.gitc990aae.el7.noarch linux-firmware-20170606-56.gitc998aae.el7.noarch
linux-firmware-20170606-56.gitc990aae.el7.noarch < linux-firmware-20170606-56.gitc998aae.el7.noarch

Atleast this tool worked for me, I hope this can be useful to others reading this article.

Please share your feedback if you face any issues with this script, we can try to make this more robust.