How to sort semantic versions in bash?

11,098

Solution 1

1. Custom script in bash

I implemented my own solution

The code a bit ugly, but it works.

Installation

$ curl -Ls https://gist.github.com/andkirby/0046df5cad44f86b670a102b7c8b7ba7/raw/version_sort_install.sh | bash
Semantic version sort: /usr/bin/semversort

$ semversort 1.0 1.0-rc 1.0-patch 1.0-alpha
1.0-alpha
1.0-rc
1.0
1.0-patch

2. Using semver in node

NOTE: All versions must follow the particular schema and it DOESN'T support "patch".

https://github.com/npm/node-semver/blob/master/README.md

$ npm install --global semver
C:\Users\u.user\.node\semver -> C:\Users\u.user\.node\node_modules\semver\bin\semver
[email protected] C:\Users\u.user\.node\node_modules\semver

$ ~/.node/semver 1.2.3 1.3.6-patch 1.3.6-beta 1.3.6 1.3.6-alpha 1.0.4
1.0.4
1.2.3
1.3.6-alpha
1.3.6-beta
1.3.6-patch
1.3.6

3. Using PHP and version_compare() in console

Also, the PHP native version_compare() (with using PHP of course :)) here.

Solution 2

Well, we could trick sort -V by adding a dummy character at the end of the string for lines that do not contain a hyphen:

$ echo "$versions" | sed '/-/!{s/$/_/}' | sort -V | sed 's/_$//'
v1.4.0-alpha
v1.4.0-alpha1
v1.4.0-patch
v1.4.0-patch2
v1.4.0-patch9
v1.4.0-patch10
v1.4.0
v1.5.0-alpha
v1.5.0-alpha1
v1.5.0-alpha2
v1.5.0-patch
v1.5.0-patch1
v1.5.0

Underscore lexically sorts after hyphen. That's the trick.

Solution 3

You can use Linux sort:

$ printf "1.0\n2.0\n2.12\n2.10\n1.2\n1.10" | sort -t "." -k1,1n -k2,2n -k3,3n
1.0
1.2
1.10
2.0
2.10
2.12

Source: https://gist.github.com/loisaidasam/b1e6879f3deb495c22cc#gistcomment-1613531

Solution 4

If you are using gplv2 (native osx) tooling, the answer by @Glenn Jack doesn't work unless using gsed.

This native awk command can substitute.

| awk '{ if ($1 ~ /-/) print; else print $0"_" ; }' |sort -rV | sed 's/_$//'

Solution 5

| sed -e 's/["\,\s]//g' \ # remove bad symbols:    1.2.3       1.2.3-123   1.2.3-patch
| sed '/-/! s/$/@999/' \ # replace releases:       1.2.3@999   1.2.3-123   1.2.3-patch
| sed 's/[\-\.]/@/g' \ # replaces separators:      1@2@3@999   1@2@3@123   1@2@3@patch
| sed 's/@patch/@9999@/' \ # replace patches:      1@2@3@999   1@2@3@123   1@2@3@9999
| sort -n -t @ -k1 -k2 -k3 -k4 \ # sort by numbers 
| sed 's/@9999@/@patch/' \  # replace back         1@2@3@999   1@2@3@123   1@2@3@patch
| sed 's/@999//' \  # replace back                 1@2@3       1@2@3@123   1@2@3@patch
| sed 's/@/./' \  # replace back                   1.2@3       1.2@3@123   1.2@3@patch
| sed 's/@/./' \  # replace back                   1.2.3       1.2.3@123   1.2.3@patch
| sed 's/@/-/'  # replace back                     1.2.3       1.2.3-123   1.2.3-patch
Share:
11,098

Related videos on Youtube

Kirby
Author by

Kirby

Updated on September 15, 2022

Comments

  • Kirby
    Kirby over 1 year

    I would like to sort semantic versions (semver.org)

    v1.4.0
    v1.4.0-alpha
    v1.4.0-alpha1
    v1.4.0-patch
    v1.4.0-patch9
    v1.4.0-patch10
    v1.4.0-patch2
    v1.5.0
    v1.5.0-alpha
    v1.5.0-alpha1
    v1.5.0-alpha2
    v1.5.0-patch
    v1.5.0-patch1
    

    in proper way. For instance, as version_compare() does in PHP (it doesn't directly, but can be used for that).

    Of course, sort -V|--version-sort doesn't work here.

    $ echo 1.0 1.0-alpha | tr ' ' "\n" | sort --version-sort
    1.0
    1.0-alpha
    

    Is there some exist approach?

    P.S.

    In common sense, it should follow this schema:

    1.0.0-alpha 
      < 1.0.0-alpha.1 
        < 1.0.0-alpha.beta 
          < 1.0.0-beta
            < 1.0.0-beta.2
              < 1.0.0-beta.11
               < 1.0.0-rc.1 < 1.0.0
                 < 1.0.0-patch < 1.0.0-patch.1.
    

    P.P.S.

    Semver 2.0 doesn't support patches, but it's needed.

    • Bruno Laturner
      Bruno Laturner almost 6 years
      The "-patch" requirement makes this incompatible with semver, so you should not call this semver. On the other hand, semver doesn't support third party patches, it's made only for official releases (in that case of a patch, the source developer should add 1 to the number in the PATCH section). If you're really pushing it, maybe it can be done with +metadata after the end of the version.
    • Kirby
      Kirby almost 6 years
      Yeah, it's true. It doesn't support "patch" type versions. About meta data - package managers DO NOT consider meta data. They cutting it off. I'm talking about composer, exactly. So, there are might be issues.
    • Kirby
      Kirby almost 6 years
      it means, it will make unexpected result, you try to get 1.0.0 version there are two version, like: 1.0.0 and 1.0.0+super-patch.
  • Kirby
    Kirby over 7 years
    True. :) So, why you've added this? :)
  • glenn jackman
    glenn jackman over 7 years
    Um, because you didn't show us your expected output?
  • Kirby
    Kirby over 7 years
    Sorry, if it's unclear. So, I've considered semver, it doesn't have patches... :( If you command will sort RC and beta, it can be an answer for question without patches.
  • shadowbq
    shadowbq about 4 years
    This can fail under macos, you should be using gsed
  • Potherca
    Potherca over 3 years
    That doesn't work if there are release candidates, for instance 2.12-rc1 would be sorted after 2.12, when it should be before it.
  • Panoptik
    Panoptik over 3 years
    Very thanks for such sort ability. It helps to sort proper semver versioning (while I not use suffixes e.g rc, alpha). My full command for fetching largest version from git looks next git for-each-ref --sort=creatordate --format '%(refname)' refs/tags | grep -E "^refs/tags/${PREFIX_DASH}[0-9]+\.[0-9]+\.[0-9]+$" | grep -E "[0-9]+\.[0-9]+\.[0-9]+" -o | sort -t "." -k1,1n -k2,2n -k3,3n | tail -n 1
  • Kyle Berezin
    Kyle Berezin over 3 years
    Thanks, this works on Snow Leopard (don't ask).
  • wisbucky
    wisbucky over 2 years
    @shadowbq It will work with mac sed if you get rid of the optional curly braces: sed '/-/! s/$/_/' (I added a space for readability.)
  • wisbucky
    wisbucky over 2 years
    If you're wondering why you can't simply add an _ to every line, it's because it would mess up the order of alpha and alpha1. alpha1_ would come before alpha_, which is wrong.
  • Nonoroazoro
    Nonoroazoro almost 2 years
    "sort -V" is the key.