How to simulate "sort -V" on Mac OSX

I have written a bash script that I need to work identically on linux and mac osx that relies on the sort command. I am piping the output of git tag -l to sort to get a list of all the version tags in the correct semantic order. GNU offers -V which makes this automagic but mac osx does not support this argument so i need to figure out how to accomplish this sort order without it.

6.3.1.1
6.3.1.10
6.3.1.11
6.3.1.2
6.3.1.3
...

needs to be sorted as

6.3.1.1
6.3.1.2
6.3.1.3
...
6.3.1.10
6.3.1.11

Answers


You can download coreUtils from http://rudix.org/packages/index.html . It contains "gnusort" with support "sort -V" sintax


sed 's/\b\([0-9]\)\b/0\1/g' versions.txt  | sort | sed 's/\b0\([0-9]\)/\1/g'

To explain why this works, consider the first sed command by itself. With your input as versions.txt, the first sed command adds a leading zero onto single-digit version numbers, producing:

06.03.01.01
06.03.01.02
06.03.01.03
06.03.01.10
06.03.01.11

The above can be sorted normally. After that, it is a matter of removing the added characters. In the full command, the last sed command removes the leading zeros to produce the final output:

6.3.1.1
6.3.1.2
6.3.1.3
6.3.1.10
6.3.1.11

The works as long as version numbers are 99 or less. If you have version numbers over 99 but less than 1000, the command gets only slightly more complicated:

sed 's/\b\([0-9]\)\b/00\1/g ; s/\b\([0-9][0-9]\)\b/0\1/g' versions.txt  | sort | sed 's/\b0\+\([0-9]\)/\1/g'

As I don't have a Mac, the above were tested on Linux.

UPDATE: In the comments, Jonathan Leffler says that even though word boundary (\b) is in Mac regex docs, Mac sed doesn't seem to recognize it. He suggests replacing the first sed with:

sed 's/^[0-9]\./0&/; s/\.\([0-9]\)$/.0\1/; s/\.\([0-9]\)\./.0\1./g; s/\.\([0-9]\)\./.0\1./g'

So, the full command might be:

sed 's/^[0-9]\./0&/; s/\.\([0-9]\)$/.0\1/; s/\.\([0-9]\)\./.0\1./g; s/\.\([0-9]\)\./.0\1./g' versions.txt | sort | sed 's/^0// ; s/\.0/./g' 

This handles version numbers up to 99.


The standard sort that comes installed on OS X can sort by fields using a separator. So you can sort the version numbers and any suffixes.

This will sort by suffix first and then by the X.Y.Z parts sort -s -t- -k 2,2n | sort -t. -s -k 1,1n -k 2,2n -k 3,3n -k 4,4n, which can also sort the -N-g format version number from the git describe --tags command

0.11.1
0.11.4
0.11.9-1-ge6b0c59
0.12.0
0.12.1
0.12.2-1-g2d0a334
0.13.0
0.13.0-1-g7711b16
0.13.0-2-g32f91bd
0.13.0-3-g83e21c5
0.14.1-alpha
0.14.1
0.14.2

The -3-g83e21c5 above is an example of a suffix that the git describe --tags command will automatically append to the latest tag to to signify the number of commits since the tag (3), and the Git SHA hash of the most recent commit (83e21c5)

To reverse the sort into descending order do this: sort -s -t- -k 2,2nr | sort -t. -s -k 1,1nr -k 2,2nr -k 3,3nr -k 4,4nr

Or you can define a shell function around it.

   version_sort() {
        # read stdin, sort by version number descending, and write stdout
        # assumes X.Y.Z version numbers

        # this will sort tags like pr-3001, pr-3002 to the END of the list
        # and tags like 2.1.4 BEFORE 2.1.4-gitsha

        sort -s -t- -k 2,2nr |  sort -t. -s -k 1,1nr -k 2,2nr -k 3,3nr -k 4,4nr
    }

or write it into a little file named version-sort, and put into some directory on your PATH. Be sure to chmod +x on the file

#!/usr/bin/env bash
sort -s -t- -k 2,2nr |  sort -t. -s -k 1,1nr -k 2,2nr -k 3,3nr -k 4,4nr

You can use additional features of git tag to get a list of tags matching a pattern and sorted properly for version tag ordering (typically no leading zeros):

$ git tag --sort v:refname
v0.0.0
v0.0.1
v0.0.2
v0.0.3
v0.0.4
v0.0.5
v0.0.6
v0.0.7
v0.0.8
v0.0.9
v0.0.10
v0.0.11
v0.0.12

From $ man git-tag:

   --sort=<type>
       Sort in a specific order. Supported type is "refname
       (lexicographic order), "version:refname" or "v:refname" 
       (tag names are treated as versions). Prepend "-" to reverse 
       sort order. When this option is not given, the sort order
       defaults to the value configured for the tag.sort variable
       if it exists, or lexicographic order otherwise. See 
       git config(1).

brew install coreutils

If corutils are installed you should have gsort on your Mac

gsort --version


Need Your Help

Either Table Rates or Shopping Cart Rule should be used for "free shipping based on zip code" to work with all methods

magento-1.5 magento magento-1.6

I want to give free shipping for certain regions with specified zip codes. How will i achieve this functionality ?

msbuild.exe works but msbuild API does not

c# visual-studio msbuild

I want to automate my builds using MSBuild API, but it gives me an error. I have my automation project in Visual Studio 2015. It references MSBuild v12.0 dlls.