18

I have to sort the following list with a shell script and make the latest version appear on the bottom or top. How would I do that with shell tools only?

release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.0
release-5.0.1
release-5.0.10
release-5.0.11
release-5.0.13
release-5.0.14
release-5.0.15
release-5.0.16
release-5.0.17
release-5.0.18
release-5.0.19
release-5.0.2
release-5.0.20
release-5.0.21
release-5.0.22
release-5.0.23
release-5.0.24
release-5.0.25
release-5.0.26
release-5.0.27
release-5.0.28
release-5.0.29
release-5.0.3
  • 1
    See also printf '%s\n' ${(on)array} in zsh. (when the list is in the $array array). – Stéphane Chazelas Mar 9 '17 at 17:50
20

GNU sort has -V that can mostly deal with a list like that (details):

 -V, --version-sort
        natural sort of (version) numbers within text

$ cat vers
release-5.0.19
release-5.0.19~pre1
release-5.0.19-bigbugfix
release-5.0.2
release-5.0.20
$ sort -V vers
release-5.0.2
release-5.0.19~pre1
release-5.0.19
release-5.0.19-bigbugfix
release-5.0.20

However, those .rc* versions could be a bit of a problem, since they probably should be sorted before the corresponding non-rc version, if there happened to be both, that is. Some versioning systems (like Debian's), use suffixes starting with a tilde (~) to mark pre-releases, and they sort before the version without a suffix, which sorts before versions with other suffixes. Apparently this is supported by at least the sort on my system, as shown above (sort (GNU coreutils) 8.23).

  • 3
    Sniped me by a couple of seconds :) – rosuav Mar 9 '17 at 16:30
  • 1
    Thanks a lot. Did not even imagine that sort would have an option like that. – Mandragor Mar 9 '17 at 16:31
  • FWIW, -V also supported by default sort on OpenBSD, but not on NetBSD. – Kusalananda Mar 9 '17 at 16:37
  • FreeBSD too, apparently, the man page there also has an example output order, and looks identical to the OpenBSD one. – ilkkachu Mar 9 '17 at 16:44
7

Check out sort -V:

   -V, --version-sort
          natural sort of (version) numbers within text

Version numbers are complicated beasts, with very few standards governing the alphabetic portions, but try this on your actual data and see if it's sufficient.

  • Wow, great! This works even for an old problem of mine with file names mayorNumber–minorNumer some text, where field sorting fails because of unicode delimiter. Thank you for the hint! – Philippos Mar 9 '17 at 16:41
3

This is can be done as one line, but split into multiple lines (at the pipes) here for readability, and handles the rc's, too.

If you don't have a -V option for your sort, or even if you do, you'll need to deal with the occasional rc's:

cat versionlist |
sed -e "s/release-//" -e "s/rc//" |
sort -t. -n -k1,1 -k2,2 -k3,3 -k4,4 |
sed -r -e "s/([^.]+)\.([^.]+)\.([^.]+)\.([^.]+)/\1.\2.\3.rc\4/" -e "s/^/release-/"

The first sed strips the non-numeric characters
The sort uses a . delimiter (-t.), numeric sort (-n), and keys (-k )
The final sed puts the non-numeric characters back in place.

0

Thanks for all the inspiration - May i propose my own answer: The sort programm can be tricked into doing what is needed. In the end it is about adding a fourth number to the the 3 digit versioning , sort it, and then remove it again. Works - simplest solution so far, IMHO.

cat versionlist |\
sed -r "s/([0-9]+\.[0-9]+\.[0-9]+$)/\1\.99999/"|sort -V|sed s/\.99999$//

result:

release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.0

....
0
$ cat /tmp/tmp.tmp
release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.0
release-5.0.1
release-5.0.10
release-5.0.11
release-5.0.13
release-5.0.14
release-5.0.15
release-5.0.16
release-5.0.17
release-5.0.18
release-5.0.19
release-5.0.2
release-5.0.20
release-5.0.21
release-5.0.22
release-5.0.23
release-5.0.24
release-5.0.25
release-5.0.26
release-5.0.27
release-5.0.28
release-5.0.29
release-5.0.3

$ cat /tmp/tmp.tmp | awk -F\- '{ print $2,$1 }' | sort -n | awk '{ print $2 "-" $1 }'
release-5.0.0
release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.1
release-5.0.10
release-5.0.11
release-5.0.13
release-5.0.14
release-5.0.15
release-5.0.16
release-5.0.17
release-5.0.18
release-5.0.19
release-5.0.2
release-5.0.20
release-5.0.21
release-5.0.22
release-5.0.23
release-5.0.24
release-5.0.25
release-5.0.26
release-5.0.27
release-5.0.28
release-5.0.29
release-5.0.3

$
  • release-5.0.0 should come AFTER .rc1 and .rc2 in the list. that is the challenge here. – Mandragor Mar 12 '17 at 8:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.