Skip to content

Instantly share code, notes, and snippets.

@andkirby
Last active January 12, 2024 15:28
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save andkirby/54204328823febad9d34422427b1937b to your computer and use it in GitHub Desktop.
Save andkirby/54204328823febad9d34422427b1937b to your computer and use it in GitHub Desktop.
Semantic versions sorting in bash.
#!/usr/bin/env bash
# Download this gist
# curl -Ls https://gist.github.com/andkirby/54204328823febad9d34422427b1937b/raw/semversort.sh | bash
# And run:
# $ semversort 1.0 1.0-rc 1.0-patch 1.0-alpha
# or in GIT
# $ semversort $(git tag)
# Using pipeline:
# $ echo 1.0 1.0-rc 1.0-patch 1.0-alpha | semversort
#
# 2016-11-03
# Released.
# 2020-03-10
# Changed regular part from "[A-z]" to "[A-Za-z]"
set -o errexit
set -o pipefail
set -o nounset
#set -o xtrace
# Script running with pipeline
if [ -z "${BASH_SOURCE[0]:-}" ]; then
__dir=/usr/local/bin
if [ ! -d ${__dir} ]; then
__dir=/usr/bin
fi
__file=${__dir}/semversort
curl -Ls https://gist.github.com/andkirby/54204328823febad9d34422427b1937b/raw/semversort.sh -o ${__file} && \
chmod u+x ${__file} && \
echo 'Semantic version sort: '${__file} && \
exit 0
exit 1
fi
if [ -t 0 ]; then
versions_list=$@
else
# catch pipeline output
versions_list=$(cat)
fi
version_weight () {
echo -e "$1" | tr ' ' "\n" | sed -e 's:\+.*$::' | sed -e 's:^v::' | \
sed -re 's:^[0-9]+(\.[0-9]+)+$:&-stable:' | \
sed -re 's:([^A-Za-z])dev\.?([^A-Za-z]|$):\1.10.\2:g' | \
sed -re 's:([^A-Za-z])(alpha|a)\.?([^A-Za-z]|$):\1.20.\3:g' | \
sed -re 's:([^A-Za-z])(beta|b)\.?([^A-Za-z]|$):\1.30.\3:g' | \
sed -re 's:([^A-Za-z])(rc|RC)\.?([^A-Za-z]|$)?:\1.40.\3:g' | \
sed -re 's:([^A-Za-z])stable\.?([^A-Za-z]|$):\1.50.\2:g' | \
sed -re 's:([^A-Za-z])pl\.?([^A-Za-z]|$):\1.60.\2:g' | \
sed -re 's:([^A-Za-z])(patch|p)\.?([^A-Za-z]|$):\1.70.\3:g' | \
sed -r 's:\.{2,}:.:' | \
sed -r 's:\.$::' | \
sed -r 's:-\.:.:'
}
tags_orig=(${versions_list})
tags_weight=( $(version_weight "${tags_orig[*]}") )
keys=$(for ix in ${!tags_weight[*]}; do
printf "%s+%s\n" "${tags_weight[${ix}]}" ${ix}
done | sort -V | cut -d+ -f2)
for ix in ${keys}; do
printf "%s\n" ${tags_orig[${ix}]}
done
@mfilotto
Copy link

mfilotto commented Jun 7, 2017

Hi,
Thanks for your script.
I get this error, any idea ?

$ ./semversort.sh 1.0 1.0-rc 1.0-patch 1.0-alpha
sed: -e expression #1, char 37: Invalid range end
sed: -e expression #1, char 43: Invalid range end
sed: -e expression #1, char 42: Invalid range end
sed: -e expression #1, char 43: Invalid range end
sed: -e expression #1, char 42: Invalid range end
sed: -e expression #1, char 36: Invalid range end
sed: -e expression #1, char 40: Invalid range end

@andkirby
Copy link
Author

andkirby commented Sep 29, 2017

@mfilotto
Oh, buddy, sorry for the silence. Perhaps, you have another version sed or I made a bug. :)
Were you able to make the fix?

@leifhetle
Copy link

leifhetle commented Nov 8, 2017

@mfilotto had the same problem, substituting "[^A-z]" with "[^a-zA-Z]" did the trick for me (Centos 7 sed 4.2.2).

@Wolvverine
Copy link

$ curl -Ls https://gist.github.com/andkirby/54204328823febad9d34422427b1937b/raw/semversort.sh | bash
Semantic version sort: /usr/local/bin/semversort
$ curl -s https://api.github.com/repos/glpi-project/glpi/releases | jq --raw-output '.[] | .tag_name' | sort --reverse | /usr/local/bin/semversort
sed: -e expression #1, char 36: Invalid range end
sed: -e expression #1, char 43: Invalid range end
sed: -e expression #1, char 40: Invalid range end
sed: -e expression #1, char 42: Invalid range end
sed: -e expression #1, char 42: Invalid range end
sed: -e expression #1, char 37: Invalid range end
sed: -e expression #1, char 43: Invalid range end

$ sed --version
sed (GNU sed) 4.2.2
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Jay Fenlason, Tom Lord, Ken Pizzini,
and Paolo Bonzini.
GNU sed home page: http://www.gnu.org/software/sed/.
General help using GNU software: http://www.gnu.org/gethelp/.
E-mail bug reports to: bug-sed@gnu.org.
Be sure to include the word sed'' somewhere in the Subject:'' field.

@Wolvverine
Copy link

Wolvverine commented Jul 23, 2018

With patch [^A-z] -> [^a-zA-Z] , is running, but x.x, beta and RC version are in wrong order:

curl -s https://api.github.com/repos/glpi-project/glpi/releases | jq --raw-output '.[] | .tag_name' | /usr/local/bin/semversort
0.85.4
0.85.5
0.90.1
0.90.2
0.90.3
0.90.4
0.90.5
0.90
9.1.1
9.1.2
9.1.3
9.1.4
9.1.5
9.1.6
9.1.7.1
9.1
9.2.1
9.2.2
9.2.3
9.2.4
9.2-RC2
9.2
9.3.0
9.3-beta
9.3-RC1
9.3-RC2

@andkirby
Copy link
Author

andkirby commented Mar 4, 2019

@leifhetle thanks for this note.
@Wolvverine, yeah, it doesn't work. But it works with this one:
https://gist.github.com/andkirby/0046df5cad44f86b670a102b7c8b7ba7/raw/version_sort_install.sh
Yeah, that's PHP function. Seems it's not what you are looking for.

Just tested sed original script on Ubuntu - it does work

# sed --version
sed (GNU sed) 4.4

@waja
Copy link

waja commented Apr 1, 2023

How about just sort -V? :)

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

@andkirby
Copy link
Author

andkirby commented Apr 2, 2023

@waja here is Stack Overflow thread:
It might help you find a proper solution which might work for you.

But in a nutshell, no, "sort -V" does not work (as initially I was needed to use -patch suffixes), you may see it in this answer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment