如何正确对具有 Major.minor.patch 级别和有时 rc 级别的列表进行排序?

如何正确对具有 Major.minor.patch 级别和有时 rc 级别的列表进行排序?

我必须使用 shell 脚本对以下列表进行排序,并使最新版本显示在底部或顶部。仅使用 shell 工具我该如何做到这一点?

release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.0
release-5.0.1
release-5.0.10
release-5.0.11
release-5.0.13
release-5.0.14
release-5.0.15
release-5.0.16
release-5.0.17
release-5.0.18
release-5.0.19
release-5.0.2
release-5.0.20
release-5.0.21
release-5.0.22
release-5.0.23
release-5.0.24
release-5.0.25
release-5.0.26
release-5.0.27
release-5.0.28
release-5.0.29
release-5.0.3

答案1

GNU 排序-V主要可以处理这样的列表(细节):

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

$ cat vers
release-5.0.19
release-5.0.19~pre1
release-5.0.19-bigbugfix
release-5.0.2
release-5.0.20
$ sort -V vers
release-5.0.2
release-5.0.19~pre1
release-5.0.19
release-5.0.19-bigbugfix
release-5.0.20

然而,这些.rc*版本可能有点问题,因为它们可能应该被排序相应的非 rc 版本,如果恰好两者都有,那就是。某些版本控制系统(例如 Debian)使用以波形符 ( ) 开头的后缀来~标记预发布版本,并且它们在不带后缀的版本之前排序,而后者在具有其他后缀的版本之前排序。显然,这至少sort在我的系统上得到支持,如上所示 ( sort (GNU coreutils) 8.23)。

要对示例列表进行排序,您可以使用以下命令:

perl -pe 's/\.(?=rc)/~/' < versions.txt | sort -V | perl -pe 's/~/./' > versions-sorted.txt

答案2

查看sort -V

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

版本号是复杂的野兽,管理字母部分的标准很少,但请在实际数据上尝试一下,看看是否足够。

答案3

这可以作为一行完成,但为了可读性,这里分成多行(在管道处),并且rc也处理 's。

如果您没有-V适合您的排序的选项,或者即使有,您也需要处理偶尔的rc问题:

cat versionlist |
    sed -e "s/release-//" -e "s/rc//" |
    sort -t. -n -k1,1 -k2,2 -k3,3 -k4,4 |
    sed -r -e "s/([^.]+)\.([^.]+)\.([^.]+)\.([^.]+)/\1.\2.\3.rc\4/" -e "s/^/release-/"
  • 第一个sed删除非数字字符。 (对于这个声明,.被认为是数字字符。)
  • sort使用一个.分隔符 ( )、数字排序 ( ),并将字段 1、2、3 和 4 枚举为键 ( )。-t.-n-k
  • 最后sed将非数字字符放回原位(假设每一个输入中的行有它们)。

答案4

对于您的示例,此方法可行。它|在应用之前向每一行添加尾随sort -V,然后删除尾随|。原因是因为sort -V命令|位于除 之外的所有 ASCII 字符之后}

$ cat versions.txt | sed 's/$/|/' | sort -V | sed 's/|$//'

release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.0
release-5.0.1
release-5.0.2
release-5.0.10
release-5.0.11

但是,如果添加release-5.0.0.rc到列表中,则需要更复杂的命令。这将暂时删除并仅向没有(或任何其他)的行release-添加尾随。|rc[a-zA-Z]

$ cat versions.txt | 
sed -e 's/^release-//' -e '/[a-zA-Z]/! s/$/|/' | 
sort -V | 
sed -e 's/^/release-/' -e 's/|$//'

release-5.0.0.rc
release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.0
release-5.0.1
release-5.0.2
release-5.0.10
release-5.0.11

相关内容