=Start=
缘由:
在逛博客的时候发现一篇好玩的文章「Bash比较版本号」,想起来之前有过类似的想法,但一直没有去实现,现在好了,有现成的版本可用了^_^
原文给出了用Bash编程实现的版本比较代码,后来我又找到了Python实现的版本,以后再看看有没有用PHP或C语言实现的版本,没有的话可以参照着自己实现一下,就当是做个练习了。
参考解答:
一个选择是sort命令(GNU coreutils >= 7):
$ sort --version sort (GNU coreutils) 8.21 Copyright (C) 2013 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 Mike Haertel and Paul Eggert. $ sort --help ... -V, --version-sort natural sort of (version) numbers within text ... $ printf '2.4.5\n2.8\n2.4.5.1\n' | sort -V 2.4.5 2.4.5.1 2.8
另一个更通用的选择是Bash编程实现(不依赖任何外部工具):
#!/bin/bash vercomp () { if [[ $1 == $2 ]] then return 0 fi local IFS=. local i ver1=($1) ver2=($2) # fill empty fields in ver1 with zeros for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) do ver1[i]=0 done for ((i=0; i<${#ver1[@]}; i++)) do if [[ -z ${ver2[i]} ]] then # fill empty fields in ver2 with zeros ver2[i]=0 fi if ((10#${ver1[i]} > 10#${ver2[i]})) then return 1 fi if ((10#${ver1[i]} < 10#${ver2[i]})) then return 2 fi done return 0 } testvercomp () { vercomp $1 $2 case $? in 0) op='=';; 1) op='>';; 2) op='<';; esac if [[ $op != $3 ]] then echo "FAIL: Expected '$3', Actual '$op', Arg1 '$1', Arg2 '$2'" else echo "Pass: '$1 $op $2'" fi } # Run tests # argument table format: # testarg1 testarg2 expected_relationship echo "The following tests should pass" while read -r test do testvercomp $test done << EOF 1 1 = 2.1 2.2 < 3.0.4.10 3.0.4.2 > 4.08 4.08.01 < 3.2.1.9.8144 3.2 > 3.2 3.2.1.9.8144 < 1.2 2.1 < 2.1 1.2 > 5.6.7 5.6.7 = 1.01.1 1.1.1 = 1.1.1 1.01.1 = 1 1.0 = 1.0 1 = 1.0.2.0 1.0.2 = 1..0 1.0 = 1.0 1..0 = EOF echo "The following test should fail (test the tester)" testvercomp 1 1 '>'
用Python实现的版本:
#!/usr/bin/env python # coding=utf-8 import re def mycmp(version1, version2): def normalize(v): return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")] return cmp(normalize(version1), normalize(version2)) assert mycmp("1", "1") == 0 assert mycmp("2.1", "2.2") < 0 assert mycmp("3.0.4.10", "3.0.4.2") > 0 assert mycmp("4.08", "4.08.01") < 0 assert mycmp("3.2.1.9.8144", "3.2") > 0 assert mycmp("3.2", "3.2.1.9.8144") < 0 assert mycmp("1.2", "2.1") < 0 assert mycmp("2.1", "1.2") > 0 assert mycmp("5.6.7", "5.6.7") == 0 assert mycmp("1.01.1", "1.1.1") == 0 assert mycmp("1.1.1", "1.01.1") == 0 assert mycmp("1", "1.0") == 0 assert mycmp("1.0", "1") == 0 assert mycmp("1.0", "1.0.1") < 0 assert mycmp("1.0.1", "1.0") > 0 assert mycmp("1.0.2.0", "1.0.2") == 0
另一个Bash编程实现的版本(暂未测试):
#!/bin/bash do_version_check() { [ "$1" == "$2" ] && return 10 ver1front=`echo $1 | cut -d "." -f -1` ver1back=`echo $1 | cut -d "." -f 2-` ver2front=`echo $2 | cut -d "." -f -1` ver2back=`echo $2 | cut -d "." -f 2-` if [ "$ver1front" != "$1" ] || [ "$ver2front" != "$2" ]; then [ "$ver1front" -gt "$ver2front" ] && return 11 [ "$ver1front" -lt "$ver2front" ] && return 9 [ "$ver1front" == "$1" ] || [ -z "$ver1back" ] && ver1back=0 [ "$ver2front" == "$2" ] || [ -z "$ver2back" ] && ver2back=0 do_version_check "$ver1back" "$ver2back" return $? else [ "$1" -gt "$2" ] && return 11 || return 9 fi } do_version_check "$1" "$2"
情况比较简单的时候可以用下面的命令试试:
$ echo '2.4.5 2.8 2.4.5.1 2.10.2' | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -k 4,4 -g
参考链接:
- How compare two strings in dot separated version format in Bash?
- Bash比较版本号
- Version number comparison
- How do I split a string on a delimiter in Bash?
=END=
《“版本号大小比较”》 有 1 条评论
sort命令中「-V」选项的说明
https://www.gnu.org/software/coreutils/manual/coreutils.html#Details-about-version-sort
PHP本身自带有版本号比较的函数(version_compare+usort)可以使用:
`
$a = array(‘2.4′,’2.3.4′,’2.4.0.9’);
usort($a, ‘version_compare’);
`
http://stackoverflow.com/questions/8690823/how-to-sort-versioning-info
http://php.net/version_compare
http://php.net/manual/en/function.usort.php
http://php.net/manual/en/function.natsort.php
http://php.net/manual/en/array.sorting.php
https://www.nutt.net/sorting-on-version-numbers-with-php/