=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/