是否有办法在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"
其他回答
你们都给出了复杂的解决方案。这里有一个更简单的例子。
function compare_versions {
local a=${1%%.*} b=${2%%.*}
[[ "10#${a:-0}" -gt "10#${b:-0}" ]] && return 1
[[ "10#${a:-0}" -lt "10#${b:-0}" ]] && return 2
a=${1:${#a} + 1} b=${2:${#b} + 1}
[[ -z $a && -z $b ]] || compare_versions "$a" "$b"
}
用法:compare_versions <ver_a> <ver_b>
返回代码1表示第一个版本大于第二个版本,2表示小于第二个版本,0表示两者相等。
也是一个非递归的版本:
function compare_versions {
local a=$1 b=$2 x y
while [[ $a || $b ]]; do
x=${a%%.*} y=${b%%.*}
[[ "10#${x:-0}" -gt "10#${y:-0}" ]] && return 1
[[ "10#${x:-0}" -lt "10#${y:-0}" ]] && return 2
a=${a:${#x} + 1} b=${b:${#y} + 1}
done
return 0
}
如果你有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
哇……这是一个老问题,但我认为这是一个相当优雅的答案。首先,使用shell参数展开(参见shell参数展开)将每个点分隔的版本转换为自己的数组。
v1="05.2.3" # some evil examples that work here
v2="7.001.0.0"
declare -a v1_array=(${v1//./ })
declare -a v2_array=(${v2//./ })
现在,这两个数组将版本号按优先级顺序作为数值字符串。上面的许多解决方案都是从这里开始的,但它们都源于这样的观察:版本字符串只是一个具有任意基数的整数。我们可以测试找到第一个不相等的数字(就像strcmp对字符串中的字符所做的那样)。
compare_version() {
declare -a v1_array=(${1//./ })
declare -a v2_array=(${2//./ })
while [[ -nz $v1_array ]] || [[ -nz $v2_array ]]; do
let v1_val=${v1_array:-0} # this will remove any leading zeros
let v2_val=${v2_array:-0}
let result=$((v1_val-v2_val))
if (( result != 0 )); then
echo $result
return
fi
v1_array=("${v1_array[@]:1}") # trim off the first "digit". it doesn't help
v2_array=("${v2_array[@]:1}")
done
# if we get here, both the arrays are empty and neither has been numerically
# different, which is equivalent to the two versions being equal
echo 0
return
}
如果第一个版本小于第二个版本,则返回负数,如果相等则返回零,如果第一个版本大于第二个版本则返回正数。一些输出:
$ compare_version 1 1.2
-2
$ compare_version "05.1.3" "5.001.03.0.0.0.1"
-1
$ compare_version "05.1.3" "5.001.03.0.0.0"
0
$ compare_version "05.1.3" "5.001.03.0"
0
$ compare_version "05.1.3" "5.001.30.0"
-27
$ compare_version "05.2.3" "7.001.0.0"
-2
$ compare_version "05.1.3" "5.001.30.0"
-27
$ compare_version "7.001.0.0" "05.1.3"
2
堕落的例子,”。2”或“3.0.”不起作用(未定义的结果),并且如果'. 2 '旁边出现非数字字符。它可能会失败(还没有测试),但肯定是没有定义的。因此,这应该与一个消毒函数或适当的检查有效的格式相匹配。此外,我相信通过一些调整,可以在没有太多额外负担的情况下使其更加健壮。
你可以递归地拆分。和下面的算法进行比较,从这里开始。如果版本相同则返回10,如果版本1大于版本2则返回11,否则返回9。
#!/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"
源
函数V -纯bash解决方案,不需要外部实用程序。 支持== = != < <= >和>=(字典)。 可选尾字母比较:1.5a < 1.5b 长度不等比较:1.6 > 1.5b 从左到右读取:如果V 1.5 '<' 1.6;然后……
<>
# Sample output
# Note: ++ (true) and __ (false) mean that V works correctly.
++ 3.6 '>' 3.5b
__ 2.5.7 '<=' 2.5.6
++ 2.4.10 '<' 2.5.9
__ 3.0002 '>' 3.0003.3
++ 4.0-RC2 '>' 4.0-RC1
<>
function V() # $1-a $2-op $3-$b
# Compare a and b as version strings. Rules:
# R1: a and b : dot-separated sequence of items. Items are numeric. The last item can optionally end with letters, i.e., 2.5 or 2.5a.
# R2: Zeros are automatically inserted to compare the same number of items, i.e., 1.0 < 1.0.1 means 1.0.0 < 1.0.1 => yes.
# R3: op can be '=' '==' '!=' '<' '<=' '>' '>=' (lexicographic).
# R4: Unrestricted number of digits of any item, i.e., 3.0003 > 3.0000004.
# R5: Unrestricted number of items.
{
local a=$1 op=$2 b=$3 al=${1##*.} bl=${3##*.}
while [[ $al =~ ^[[:digit:]] ]]; do al=${al:1}; done
while [[ $bl =~ ^[[:digit:]] ]]; do bl=${bl:1}; done
local ai=${a%$al} bi=${b%$bl}
local ap=${ai//[[:digit:]]} bp=${bi//[[:digit:]]}
ap=${ap//./.0} bp=${bp//./.0}
local w=1 fmt=$a.$b x IFS=.
for x in $fmt; do [ ${#x} -gt $w ] && w=${#x}; done
fmt=${*//[^.]}; fmt=${fmt//./%${w}s}
printf -v a $fmt $ai$bp; printf -v a "%s-%${w}s" $a $al
printf -v b $fmt $bi$ap; printf -v b "%s-%${w}s" $b $bl
case $op in
'<='|'>=' ) [ "$a" ${op:0:1} "$b" ] || [ "$a" = "$b" ] ;;
* ) [ "$a" $op "$b" ] ;;
esac
}
代码解释
第1行:定义局部变量:
A, op, b -比较操作数和操作符,即"3.6" > "3.5a"。 Al, a和b的bl尾字母,初始化为尾项,即“6”和“5a”。
第2行和第3行:从尾部项目中向左修剪数字,因此如果有字母,则只剩下“”和“a”。
第4行:右修剪a和b中的字母,只保留数字项的序列作为局部变量ai和bi,即“3.6”和“3.5”。 值得注意的例子:"4.01-RC2" > "4.01-RC1"得到ai="4.01" al="-RC2"和bi="4.01" bl="-RC1"。
第6行:定义局部变量:
Ap, bp - 0 ai和bi的右填充。首先只保留项间点,其中点的数量分别等于a和b的元素的数量。
第7行:然后在每个点后面添加“0”来制作填充蒙版。
第9行:局部变量:
W -项目宽度 FMT - printf格式字符串,待计算 X -暂时 IFS =。Bash以“。”分隔变量值。
第10行:计算w,最大条目宽度,它将用于对齐条目进行字典比较。在我们的例子中w=2。
第11行:通过替换$a中的每个字符创建printf对齐格式。w b美元% ${},即,“3.6”>“3.5”收益率“% 2 s % 2 s % 2 s % 2 s”。
第12行:"printf -v a"设置变量a的值。这相当于许多编程语言中的a=sprintf(…)。注意这里,通过IFS=的影响。printf的参数拆分为单独的项。
在第一个printf中,a中的项用空格左填充,同时从bp中追加足够多的“0”项,以确保结果字符串a可以与类似格式的b进行有意义的比较。
请注意,我们将bp -而不是ap附加到ai,因为ap和bp可能有不同的长度,所以这导致a和b具有相同的长度。
对于第二个printf,我们将字母部分al附加到a,并使用足够的填充来进行有意义的比较。现在a可以和b比较了。
第13行:与第12行相同,但b。
第15行:在非内置(<=和>=)操作符和内置操作符之间分割比较情况。
第16行:如果比较操作符<=,则分别测试a<b或a=b - >= a<b或a=b
第17行:测试内置比较操作符。
<>
# All tests
function P { printf "$@"; }
function EXPECT { printf "$@"; }
function CODE { awk $BASH_LINENO'==NR{print " "$2,$3,$4}' "$0"; }
P 'Note: ++ (true) and __ (false) mean that V works correctly.\n'
V 2.5 '!=' 2.5 && P + || P _; EXPECT _; CODE
V 2.5 '=' 2.5 && P + || P _; EXPECT +; CODE
V 2.5 '==' 2.5 && P + || P _; EXPECT +; CODE
V 2.5a '==' 2.5b && P + || P _; EXPECT _; CODE
V 2.5a '<' 2.5b && P + || P _; EXPECT +; CODE
V 2.5a '>' 2.5b && P + || P _; EXPECT _; CODE
V 2.5b '>' 2.5a && P + || P _; EXPECT +; CODE
V 2.5b '<' 2.5a && P + || P _; EXPECT _; CODE
V 3.5 '<' 3.5b && P + || P _; EXPECT +; CODE
V 3.5 '>' 3.5b && P + || P _; EXPECT _; CODE
V 3.5b '>' 3.5 && P + || P _; EXPECT +; CODE
V 3.5b '<' 3.5 && P + || P _; EXPECT _; CODE
V 3.6 '<' 3.5b && P + || P _; EXPECT _; CODE
V 3.6 '>' 3.5b && P + || P _; EXPECT +; CODE
V 3.5b '<' 3.6 && P + || P _; EXPECT +; CODE
V 3.5b '>' 3.6 && P + || P _; EXPECT _; CODE
V 2.5.7 '<=' 2.5.6 && P + || P _; EXPECT _; CODE
V 2.4.10 '<' 2.4.9 && P + || P _; EXPECT _; CODE
V 2.4.10 '<' 2.5.9 && P + || P _; EXPECT +; CODE
V 3.4.10 '<' 2.5.9 && P + || P _; EXPECT _; CODE
V 2.4.8 '>' 2.4.10 && P + || P _; EXPECT _; CODE
V 2.5.6 '<=' 2.5.6 && P + || P _; EXPECT +; CODE
V 2.5.6 '>=' 2.5.6 && P + || P _; EXPECT +; CODE
V 3.0 '<' 3.0.3 && P + || P _; EXPECT +; CODE
V 3.0002 '<' 3.0003.3 && P + || P _; EXPECT +; CODE
V 3.0002 '>' 3.0003.3 && P + || P _; EXPECT _; CODE
V 3.0003.3 '<' 3.0002 && P + || P _; EXPECT _; CODE
V 3.0003.3 '>' 3.0002 && P + || P _; EXPECT +; CODE
V 4.0-RC2 '>' 4.0-RC1 && P + || P _; EXPECT +; CODE
V 4.0-RC2 '<' 4.0-RC1 && P + || P _; EXPECT _; CODE