The Shell Scripting Tutorial


RPM Package Versions

A nice way to accurately determine and parse an RPM package version

14 May 2015

A nice technique to split out an RPM package version, such as "1.12.14" into an array. Adapted from a Red Hat Satellite katello-ca-consumer package. This makes it easier to query the version, since "1.12.14" is not a real number and doesn't lend itself to comparison tests.

$ PACKAGE=subscription-manager
$ rpm -q --queryformat='%{VERSION}' $PACKAGE
1.12.14
$ PACKAGE_VERSION="`rpm -q --queryformat='%{VERSION}' $PACKAGE | tr . ' '`"
$ echo $PACKAGE_VERSION
1 12 14
$ declare -a PACKAGE_VERSION_ARRAY=($PACKAGE_VERSION)
$ echo ${PACKAGE_VERSION_ARRAY[0]}
1
$ echo ${PACKAGE_VERSION_ARRAY[1]}
12
$ echo ${PACKAGE_VERSION_ARRAY[2]}
14
$

This can be useful as the basis of a tool to compare installed RPM packages between systems, for example. It also avoids the other problem with RPM package names. To take two packages at random:

  • tsdb-1.27.29-1.el6.noarch.rpm
  • yum-rhn-plugin-2.2.7-1.el6.noarch.rpm

It is clear that the hyphen () separates the package-name from the version and release number. But because yum-rhn-plugin also contains hyphens, it is not easy to split out the package name from the version. This rpm -q --queryformat approach is guaranteed to get the version number.

Package Name

There is a second, somewhat-related problem associated with working out the package name. Because a name like "yum-rhn-plugin-2.2.7-1.el6.noarch.rpm" as mentioned above, contains multiple hyphens in the actual package name (yum-rhn-plugin), it is not possible to use a simple "cut" to extract the package name. Consider these packages:

  • net-tools-2.0-0.17.20131004git.el7.x86_64
  • pinentry-0.8.1-14.el7.x86_64
  • yum-cron-3.4.3-132.el7.centos.0.1.noarch
  • libselinux-utils-2.2.2-6.el7.x86_64
  • libmpc-1.0.1-3.el7.x86_64

Although these do follow a logical pattern which is easy enough for a person to understand, it is not so obvious how to code it. You can't use "cut" alone, because although ostensibly the delimiter is the hypen (-), that is also a valid character in the package name itself.

One solution is to use "cut" along with the less well-known "rev" utility (from util-linux). This approach makes use of the fact that the total number of fields is fixed, and that the name comes at the beginning:

#!/bin/sh
for fullname in `cat /tmp/rpmlist.txt`
do
  echo -n "The package name in \"$fullname\" is: "
  echo $fullname | rev | cut -d'-' -f3- | rev
done
The package name in "net-tools-2.0-0.17.20131004git.el7.x86_64" is: net-tools
The package name in "pinentry-0.8.1-14.el7.x86_64" is: pinentry
The package name in "yum-cron-3.4.3-132.el7.centos.0.1.noarch" is: yum-cron
The package name in "libselinux-utils-2.2.2-6.el7.x86_64" is: libselinux-utils
The package name in "libmpc-1.0.1-3.el7.x86_64" is: libmpc
$

This reverses the string, then cuts out the first two fields (version and 'release.os.arch'). Then it reverses the string again to get everything back as it should be.


My Paperbacks and eBooks

My Shell Scripting books, available in Paperback and eBook formats. This tutorial is more of a general introduction to Shell Scripting, the longer Shell Scripting: Expert Recipes for Linux, Bash and more book covers every aspect of Bash in detail.

Shell Scripting Tutorial

Shell Scripting Tutorial
is this tutorial, in 88-page Paperback and eBook formats. Convenient to read on the go, and in paperback format good to keep by your desk as an ever-present companion.

Also available in PDF form from Gumroad:Get this tutorial as a PDF
Shell Scripting: Expert Recipes for Linux, Bash and more

Shell Scripting: Expert Recipes for Linux, Bash and more
is my 564-page book on Shell Scripting. The first half covers all of the features of the shell in every detail; the second half has real-world shell scripts, organised by topic, along with detailed discussion of each script.