是否有办法在bash上比较这些字符串,例如:2.4.5和2.8和2.4.5.1?
当前回答
函数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
其他回答
function version_compare () {
function sub_ver () {
local len=${#1}
temp=${1%%"."*} && indexOf=`echo ${1%%"."*} | echo ${#temp}`
echo -e "${1:0:indexOf}"
}
function cut_dot () {
local offset=${#1}
local length=${#2}
echo -e "${2:((++offset)):length}"
}
if [ -z "$1" ] || [ -z "$2" ]; then
echo "=" && exit 0
fi
local v1=`echo -e "${1}" | tr -d '[[:space:]]'`
local v2=`echo -e "${2}" | tr -d '[[:space:]]'`
local v1_sub=`sub_ver $v1`
local v2_sub=`sub_ver $v2`
if (( v1_sub > v2_sub )); then
echo ">"
elif (( v1_sub < v2_sub )); then
echo "<"
else
version_compare `cut_dot $v1_sub $v1` `cut_dot $v2_sub $v2`
fi
}
### Usage:
version_compare "1.2.3" "1.2.4"
# Output: <
功劳归于@Shellman
函数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
与其编写冗长的代码使您的生活过于复杂,不如使用一些已经存在的东西。很多时候,当bash不够用时,python可以提供帮助。你仍然可以很容易地从bash脚本调用它(额外的好处:从bash到python的变量替换):
VERSION1=1.2.3
VERSION2=1.2.4
cat <<EOF | python3 | grep -q True
from packaging import version
print(version.parse("$VERSION1") > version.parse("$VERSION2"))
EOF
if [ "$?" == 0 ]; then
echo "$VERSION1 is greater than $VERSION2"
else
echo "$VERSION2 is greater or equal than $VERSION1"
fi
这里有更多信息:如何比较Python中的版本号?
可能没有普遍正确的方法来实现这一点。如果您正在尝试比较Debian包系统中的版本,请尝试dpkg——compare-versions <first> <relation> <second>。
如果它只是想知道一个版本是否比另一个版本低,我会检查sort——version-sort是否会改变我的版本字符串的顺序:
string="$1
$2"
[ "$string" == "$(sort --version-sort <<< "$string")" ]