Reputation: 3117
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.
Upvotes: 42
Views: 21404
Reputation: 1
There are quite few 'jq' solutions around. Within my searches, this one from @JanB impressed the most.
Other people have outlined about how to extract floating point numbers from text. This one on Stack for instance.
In the end I wrote a short script program with a CLI interface that can be run as standalone or embedded.
floatversion -M "$(curl -sf "https://github.com/TuxVinyards/floatversion/releases" | grep 's/tag')"
1.0.0
floatversion -r "$(curl -sf https://github.com/qemu/qemu/tags | grep 's/tag')"
9.1.1 9.1.0 9.0.3 8.2.7 7.2.14
floatversion -M "$(curl -sf https://github.com/qemu/qemu/tags | grep 's/tag')"
9.1.1
floatversion --options "quoted-input-source"
Extracts point separated numbers, or semantic version numbers with optional suffixes,
and other common variations upon, from a given string or text-file
-h | --help show help
-V | --version show version
-c | --col show list as column instead of string (unless -M)
-r | --rev show list in reverse order
-a | --all show all extracted values, not just unique
-n | --num sort by standard numbering, not versioning
-f | --full check for additional sem. ver. suffixes, eg. -beta
-F | --filter contains given items -F "string string string"
-S | --starts starting with -S "string string string"
-D | --delete doesn't contain: -D "string string string"
-M | --max outputs the highest/latest value in list, only, with '-r' shows lowest/earliest
-g | --gt A > B, returns true/false -g "A B" (.nums or sem ver, for -lt use B A)
-v | --verbose for problem output, show algorithm sequences (full version only)
--sort-v use sort -V (if present) in preference to the default jq methods
--no-svb no falling back to 'jq' if 'sort -V' is unavailable, show error instead
Without options, produces a single sorted string of all unique items found
Filters output as string, column or max. Post-output grep requires columns.
Tests show 'jq' sort methods as more reliable than 'sort -V' esp. with alpha suffixes
All cases, returns false if none
On GitHub here
Upvotes: 0
Reputation: 85
semantic versions sort with jq:
# test: versions using example on https://semver.org in reversed order
echo "v1.0.0 v1.0.0-rc.1 v1.0.0-beta.11 v1.0.0-beta.2 v1.0.0-beta v1.0.0-alpha.beta v1.0.0-alpha.1 v1.0.0-alpha "\
| while read -d" " version; do echo $version; done \
| jq -Rrn '
# read input lines as an array
[inputs]
|sort_by(
# extract name and version
match("[0-9]+[0-9.]*";"").offset as $version_index
|.[:$version_index] as $name
|.[$version_index:]
# ignore build
|split("+")[0]
# extract version core and pre-release as arrays of numbers and strings
|split("-")
|(.[0]|split(".")|map(tonumber? // .)) as $version_core
|(.[1:]|join("-")|split(".")|map(tonumber? // .)) as $pre_release
# sort by name
|$name,
# sort by version core
$version_core,
# pre-release versions have a lower precedence than the associated normal version
($pre_release|length)==0,
# sort by pre-release
$pre_release
)
#extract values from an array
|.[]'
v1.0.0-alpha
v1.0.0-alpha.1
v1.0.0-alpha.beta
v1.0.0-beta
v1.0.0-beta.2
v1.0.0-beta.11
v1.0.0-rc.1
v1.0.0
Upvotes: 1
Reputation: 247012
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.
Handling patches can use he same strategy: replace the hyphen with an underscore, and restore it after sorting
cat << VERSIONS | sed '/-/!{s/$/_/;}; s/-patch/_patch/' | sort -V | sed 's/_$//; s/_patch/-patch/'
v1.4.0-alpha
v1.4.0-alpha1
v1.4.0-beta
v1.4.0-patch
v1.4.0-patch2
v1.4.0-patch9
v1.4.0-patch10
v1.4.0-rc1
v1.4.0
v1.5.0-alpha
v1.5.0-alpha2
v1.5.0-alpha1
v1.5.0-beta
v1.5.0-patch
v1.5.0-patch1
v1.5.0-beta2
v1.5.0
VERSIONS
outputs
v1.4.0-alpha
v1.4.0-alpha1
v1.4.0-beta
v1.4.0-rc1
v1.4.0
v1.4.0-patch
v1.4.0-patch2
v1.4.0-patch9
v1.4.0-patch10
v1.5.0-alpha
v1.5.0-alpha1
v1.5.0-alpha2
v1.5.0-beta
v1.5.0-beta2
v1.5.0
v1.5.0-patch
v1.5.0-patch1
Upvotes: 47
Reputation: 21
| 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
Upvotes: 2
Reputation: 3117
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.
Upvotes: 3
Reputation: 1072
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
Upvotes: 28
Reputation: 1459
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/_$//'
Upvotes: 2
Reputation: 49
curl -s https://api.github.com/repos/glpi-project/glpi/releases | jq --raw-output '.[] | .tag_name' | sed '/-/!{s/$/_/}' | sort -V | sed 's/_$//'
This does not correct show versions.
Upvotes: 2