如何在 bash 中对语义版本进行排序?

问题描述 投票:0回答:7

我想对语义版本进行排序(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

以正确的方式。例如,正如

version_compare()
在 PHP 中所做的那样(它不是直接使用,但可以用于此目的)。

当然,

sort -V|--version-sort
在这里不起作用。

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

有一些现有的方法吗?

附注

按照常识,它应该遵循以下模式:

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不支持补丁,但需要。

bash sorting version semantic-versioning
7个回答
38
投票

好吧,我们可以通过在不包含连字符的行的字符串末尾添加一个虚拟字符来欺骗

sort -V

$ 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

下划线在词法上对 after 连字符进行排序。这就是窍门。


处理补丁可以使用同样的策略:将连字符替换为下划线,排序后恢复

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

输出

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

28
投票

您可以使用Linux排序:

$ 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

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


3
投票

1。 bash 中的自定义脚本

我实施了我自己的解决方案

代码有点难看,但是可以用。

安装

$ 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。在节点中使用semver

注意:所有版本必须遵循特定架构,并且不支持“补丁”。

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.在控制台中使用 PHP 和 version_compare()

此外,PHP 原生

version_compare()
(当然使用 PHP :))这里


2
投票
| 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

1
投票
curl -s https://api.github.com/repos/glpi-project/glpi/releases | jq --raw-output '.[] | .tag_name' |  sed '/-/!{s/$/_/}' | sort -V | sed 's/_$//'

这不会正确显示版本。


1
投票

如果您使用 gplv2(本机 osx)工具,除非使用 gsed,否则@Glenn Jack 的答案将不起作用。

这个原生 awk 命令可以替代。

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

0
投票

jq 中实现的语义版本排序:

# test: versions from example on https://semver.org in reversed order
echo "1.0.0 1.0.0-rc.1 1.0.0-beta.11 1.0.0-beta.2 1.0.0-beta 1.0.0-alpha.beta 1.0.0-alpha.1 1.0.0-alpha "\
| while read -d" " version; do echo $version; done \
| jq -Rrn '
# read input lines as an array
[inputs]
|sort_by(
  # ignore build
  split("+")[0]
  # extract version core and pre-release
  |split("-")
  |(.[0]|split(".")|map(tonumber? // .)) as $version_core
  |(.[1:]|join("-")|split(".")|map(tonumber? // .)) as $pre_release
  # 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
|.[]'
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
© www.soinside.com 2019 - 2024. All rights reserved.