如何对具有major.minor.patch级别的列表进行排序,有时还可以正确地对rc进行排序?


18

我必须使用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
另见printf '%s\n' ${(on)array}zsh。(当列表在$array数组中时)。
斯特凡Chazelas

Answers:


20

GNU sort具有-V大部分可以处理这样的列表的细节details):

 -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)所示。


3
nip了我几秒钟:)
rosuav

1
非常感谢。甚至没有想到那种排序会有这样的选择。
Mandragor

-V默认情况下sort,OpenBSD 也支持FWIW,但NetBSD不支持。
库沙兰丹

FreeBSD显然也是如此,那里的手册页也有一个示例输出顺序,并且看上去与OpenBSD相同。
ilkkachu

7

签出sort -V

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

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


哇,太好了!即使是我的一个老文件名问题,mayorNumber–minorNumer some text由于Unicode分隔符而导致字段排序失败,这仍然有效。谢谢你的提示!
Philippos

3

可以将其作为一行完成,但为了便于阅读,此处又分成了多行(在管道处),并且也处理了rc

如果您没有-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使用.定界符(-t.),数字排序(- n)和键(-k
。最后一个sed将非数字字符放回原处。


0

感谢所有的灵感-我可以提出我自己的答案:可以诱使排序程序执行所需的操作。最后,它是要在3位数版本控制中添加第四个数字,对其进行排序,然后再次将其删除。可行-到目前为止,最简单的解决方案,恕我直言。

cat versionlist |\
sed -r "s/([0-9]+\.[0-9]+\.[0-9]+$)/\1\.99999/"|sort -V|sed s/\.99999$//

结果:

release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.0

....

0
$ cat /tmp/tmp.tmp
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

$ cat /tmp/tmp.tmp | awk -F\- '{ print $2,$1 }' | sort -n | awk '{ print $2 "-" $1 }'
release-5.0.0
release-5.0.0.rc1
release-5.0.0.rc2
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

$

release-5.0.0应该在列表中的.rc1和.rc2之后。这就是这里的挑战。
Mandragor
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.