=Start=
缘由:
在逛博客的时候发现一篇好玩的文章「 Bash比较版本号 」,想起来之前有过类似的想法,但一直没有去实现,现在好了,有现成的版本可用了^_^
原文给出了用Bash编程实现的版本比较代码,后来我又找到了Python实现的版本,以后再看看有没有用PHP或C语言实现的版本,没有的话可以参照着自己实现一下,就当是做个练习了。
参考解答:
一个选择是sort命令(GNU coreutils >= 7):
$ sort --version
sort (GNUcoreutils) 8.21
Copyright (C) 2013 FreeSoftwareFoundation, Inc.
LicenseGPLv3+: GNUGPLversion 3 or later .
This is freesoftware: youarefreeto changeand redistributeit.
Thereis NOWARRANTY, to theextentpermittedbylaw.
WrittenbyMikeHaerteland PaulEggert.
$ sort --help
...
-V, --version-sortnaturalsortof (version) numberswithintext
...
$ 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
localIFS=.
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
11=
2.12.2<
3.0.4.103.0.4.2>
4.084.08.01<
3.2.1.9.8144 3.2>
3.23.2.1.9.8144 <
1.22.1<
2.11.2>
5.6.75.6.7=
1.01.11.1.1=
1.1.11.01.1=
11.0=
1.01=
1.0.2.01.0.2=
1..01.0=
1.01..0=
EOF
echo "The following test should fail (test the tester)"
testvercomp 1 1 '>'
用Python实现的版本:
#!/usr/bin/env python
# coding=utf-8
importre
defmycmp(version1, version2):
defnormalize(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
参考链接:
=END=