是否有办法在bash上比较这些字符串,例如:2.4.5和2.8和2.4.5.1?
当前回答
这个怎么样?似乎有用?
checkVersion() {
subVer1=$1
subVer2=$2
[ "$subVer1" == "$subVer2" ] && echo "Version is same"
echo "Version 1 is $subVer1"
testVer1=$subVer1
echo "Test version 1 is $testVer1"
x=0
while [[ $testVer1 != "" ]]
do
((x++))
testVer1=`echo $subVer1|cut -d "." -f $x`
echo "testVer1 now is $testVer1"
testVer2=`echo $subVer2|cut -d "." -f $x`
echo "testVer2 now is $testVer2"
if [[ $testVer1 -gt $testVer2 ]]
then
echo "$ver1 is greater than $ver2"
break
elif [[ "$testVer2" -gt "$testVer1" ]]
then
echo "$ver2 is greater than $ver1"
break
fi
echo "This is the sub verion for first value $testVer1"
echo "This is the sub verion for second value $testVer2"
done
}
ver1=$1
ver2=$2
checkVersion "$ver1" "$ver2"
其他回答
ver_cmp()
{
local IFS=.
local V1=($1) V2=($2) I
for ((I=0 ; I<${#V1[*]} || I<${#V2[*]} ; I++)) ; do
[[ ${V1[$I]:-0} -lt ${V2[$I]:-0} ]] && echo -1 && return
[[ ${V1[$I]:-0} -gt ${V2[$I]:-0} ]] && echo 1 && return
done
echo 0
}
ver_eq()
{
[[ $(ver_cmp "$1" "$2") -eq 0 ]]
}
ver_lt()
{
[[ $(ver_cmp "$1" "$2") -eq -1 ]]
}
ver_gt()
{
[[ $(ver_cmp "$1" "$2") -eq 1 ]]
}
ver_le()
{
[[ ! $(ver_cmp "$1" "$2") -eq 1 ]]
}
ver_ge()
{
[[ ! $(ver_cmp "$1" "$2") -eq -1 ]]
}
测试:
( ( while read V1 V2 ; do echo $V1 $(ver_cmp $V1 $V2) $V2 ; done ) <<EOF
1.2.3 2.2.3
2.2.3 2.2.2
3.10 3.2
2.2 2.2.1
3.1 3.1.0
EOF
) | sed 's/ -1 / < / ; s/ 0 / = / ; s/ 1 / > /' | column -t
1.2.3 < 2.2.3
2.2.3 > 2.2.2
3.10 > 3.2
2.2 < 2.2.1
3.1 = 3.1.0
ver_lt 10.1.2 10.1.20 && echo 'Your version is too old'
Your version is too old
下面是一个不需要任何外部工具的纯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 '>'
运行测试:
$ . ./vercomp
The following tests should pass
Pass: '1 = 1'
Pass: '2.1 < 2.2'
Pass: '3.0.4.10 > 3.0.4.2'
Pass: '4.08 < 4.08.01'
Pass: '3.2.1.9.8144 > 3.2'
Pass: '3.2 < 3.2.1.9.8144'
Pass: '1.2 < 2.1'
Pass: '2.1 > 1.2'
Pass: '5.6.7 = 5.6.7'
Pass: '1.01.1 = 1.1.1'
Pass: '1.1.1 = 1.01.1'
Pass: '1 = 1.0'
Pass: '1.0 = 1'
Pass: '1.0.2.0 = 1.0.2'
Pass: '1..0 = 1.0'
Pass: '1.0 = 1..0'
The following test should fail (test the tester)
FAIL: Expected '>', Actual '=', Arg1 '1', Arg2 '1'
我实现了一个函数,返回与Dennis Williamson相同的结果,但使用更少的行数。它最初执行一个健全性检查,导致1..0从他的测试中失败(我认为应该是这样),但他所有的其他测试都通过了这段代码:
#!/bin/bash
version_compare() {
if [[ $1 =~ ^([0-9]+\.?)+$ && $2 =~ ^([0-9]+\.?)+$ ]]; then
local l=(${1//./ }) r=(${2//./ }) s=${#l[@]}; [[ ${#r[@]} -gt ${#l[@]} ]] && s=${#r[@]}
for i in $(seq 0 $((s - 1))); do
[[ ${l[$i]} -gt ${r[$i]} ]] && return 1
[[ ${l[$i]} -lt ${r[$i]} ]] && return 2
done
return 0
else
echo "Invalid version number given"
exit 1
fi
}
如果你有coreutils-7 (Ubuntu Karmic,而不是Jaunty),那么你的排序命令应该有一个-V选项(版本排序),你可以使用它来进行比较:
verlte() {
[ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
}
verlt() {
[ "$1" = "$2" ] && return 1 || verlte $1 $2
}
verlte 2.5.7 2.5.6 && echo "yes" || echo "no" # no
verlt 2.4.10 2.4.9 && echo "yes" || echo "no" # no
verlt 2.4.8 2.4.10 && echo "yes" || echo "no" # yes
verlte 2.5.6 2.5.6 && echo "yes" || echo "no" # yes
verlt 2.5.6 2.5.6 && echo "yes" || echo "no" # no
下面是另一个纯bash版本,比公认的答案要小得多。它只检查版本是否小于或等于“最小版本”,并且它将按字典顺序检查字母数字序列,这通常会给出错误的结果(举个常见的例子,“snapshot”不晚于“release”)。它将工作的主要/次要。
is_number() {
case "$BASH_VERSION" in
3.1.*)
PATTERN='\^\[0-9\]+\$'
;;
*)
PATTERN='^[0-9]+$'
;;
esac
[[ "$1" =~ $PATTERN ]]
}
min_version() {
if [[ $# != 2 ]]
then
echo "Usage: min_version current minimum"
return
fi
A="${1%%.*}"
B="${2%%.*}"
if [[ "$A" != "$1" && "$B" != "$2" && "$A" == "$B" ]]
then
min_version "${1#*.}" "${2#*.}"
else
if is_number "$A" && is_number "$B"
then
[[ "$A" -ge "$B" ]]
else
[[ ! "$A" < "$B" ]]
fi
fi
}