Extract latest version from xml file using shell script

Viewed 518

I am trying to get the latest artifact number from my repository, I can't use the <release>3.4.6.17</release> tag because I want to control the version which I'm taking the latest version from.

For example in this maven-metadata.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <groupId>com.company.platform</groupId>
  <artifactId>platform</artifactId>
  <versioning>
    <release>3.4.6.17</release>
    <versions>
      <version>3.3.0.89</version>
      <version>3.3.17.65</version>
      <version>3.3.17.66</version>
      <version>3.3.19.65</version>
      <version>3.4.2.70</version>
      <version>3.4.2.71</version>
      <version>3.4.4.39</version>
      <version>3.4.4.40</version>
      <version>3.4.4.41</version>
      <version>3.4.4.42</version>
      <version>3.4.6.1</version>
      <version>3.4.6.2</version>
      <version>3.4.6.3</version>
      <version>3.4.6.4</version>
      <version>3.4.6.16</version>
      <version>3.4.6.17</version>
    </versions>
    <lastUpdated>20201011113748</lastUpdated>
  </versioning>
</metadata>

I want to get the latest of the 3.4.4 versions, which is: 3.4.4.42.

And not the latest uploaded artifact which is: 3.4.6.17.

Is there a way in a shell script to parse that file by a given version (version=3.3.4)?

3 Answers

grep

If this xml file is always so flat, you could use grep with PCRE to match the text inside the version node, and then do version sorting -V with GNU sort and get the newer version for your input pattern:

grep -oP '(?<=<version>)3\.4\.4.*?(?=</version>)' file.xml | sort -V | tail -1
3.4.4.42

xmlstarlet

Usually you can find many tools in a shell that can parse xml files and select any part of them, like xmllint, xpath, xmlstarlet etc. They don't parse just text and this is the right and safer approach. Here is an example:

xmlstarlet sel -t -m '//version[starts-with(., "3.4.4")]' -v . -n file.xml
3.4.4.39
3.4.4.40
3.4.4.41
3.4.4.42

and again you can pipe the above to sort -V.

cat test.xml | grep -E "<version>3\.4\.4.*</version>" | sort | tail -n 1 | sed 's/<.*>\(.*\)<\/.*>/\1/g' | tr -d [:blank:]
  1. list the contents of the xml file
  2. search for versions beginning with 3.3.4 ...
  3. sort the results
  4. keep only the last element (latest version)
  5. remove the xml tags with sed
  6. remove the whitespace characters like tab or space

Assumptions:

  • OP does not have access to a XML parser
  • the input file is formatted as displayed in the question
  • versions are ordered oldest (earlier in file) to newest (later in file) so as we find matches we just need to keep the latest match

One awk solution:

$ baseversion='3.4.4'
$ awk -F'[><]' -v bv="^${baseversion}" '             # use ">" and "<" as input field delimiters; build search pattern "^{baseversion}" and pass in as variable "bv"
$2=="version" && $3 ~ bv { latestversion=$3 }        # if field2 equals the string "version" and field3 starts with our "^baseversion" pattern then save field3 in "latestversion"
END                      { print latestversion }     # print the latest version
' maven*xml
3.4.4.42

Single line with comments removed:

$ awk -F'[><]' -v bv="^${baseversion}" '$2=="version" && $3 ~ bv { latestversion=$3 } END { print latestversion }' maven*xml
3.4.4.42
Related