How to get the latest patch-level version from a list of distinct versions using bash and awk. This idea was taken from https://stackoverflow.com/a/21103864/1006369
Supose you have the following list of versions:
v1.22.8
v1.22.9
v1.22.10 <-- latest v1.22 series
v1.23.1
v1.23.2 <-- latest v1.23 series
v1.24.1
v1.24.2
v1.24.3
v1.24.4 <-- latest v1.24 series
And you need to extract the latest PATCH of each version series. The result thus must be this:
v1.22.10
v1.23.2
v1.24.4
Using AWK's pattern expressions it's possible to evaluate only the first element of a associative-array, negate the eval and print (by default):
First, create the file with the versions. It doesn't matter if it's sorted or not yet.
$ cat >versions.txt <<EOF
v1.22.8
v1.22.9
v1.22.10
v1.23.1
v1.23.2
v1.24.1
v1.24.2
v1.24.3
v1.24.4
EOF
Use sort's flags -V
to sort by version number and -r
to reverse the sorted values, from newest to oldest:
sort -Vr versions.txt
v1.24.4
v1.24.3
v1.24.2
v1.24.1
v1.23.2
v1.23.1
v1.22.10
v1.22.9
v1.22.8
Sending this output to awk
gives the latest version of each series:
$ sort -Vr versions.txt | awk -F . '!a[$1 FS $2]++'
v1.24.4
v1.23.2
v1.22.10
Let's analyse what awk
does:
-F .
: Uses.
as the field separator. Each line will be splited by.
, creating 3 fields:$1=v1
(3 times),$2=24|23|22
and$3=4|2|10
.a[$1 FS $2]
: Creates an associative arraya
at position$1 FS $2
(the values are concatenated), where$1=v1
and$2=24
(ex, at the first input line), andFS
if the field-separator (.
). Since this posistion doesn't exists, awk initializes it withnull
.a[$1 FS $2]++
: Postfix-increments the value from0
(null
) to1
, turning it into atrue
value. The value0
is used for the next instruction!
and1
is stored ata[$1 FS $2]
.!a[$1 FS $2]++
: Negates the value0
(false
) to1
(true
), accepting the expression and printing the line.
This is just an expression to accept code blocks to execute. When the code block is not defined, like this one, the default {print}
is executed.
At the next line for the same $1.$2
index, the value will be 1
, thus negating it (!
) will change it to 0
, which evaluates to false
, avoinding the default {print}
code block. Any other match for $1.$2
will produce a false
evaluation.
Note this only works if the input lines are sorted with the newest patch first, since awk will basically filter for the first item it finds.
If you need to have the list sorted from oldest to newest, just use sort -V
again:
$ sort -Vr versions.txt | awk -F . '!a[$1 FS $2]++' | sort -V
v1.22.10
v1.23.2
v1.24.4
Genius!