提问人:Shubham Jain 提问时间:7/26/2023 最后编辑:Shubham Jain 更新时间:7/27/2023 访问量:124
字符串到浮点数的比较在 shell 脚本中不起作用
String to float comparison not working in shell script
问:
字符串到浮动的比较在 shell 脚本中不起作用
REQUIRED_VERSION=2.38.0
VERSION=$(echo $FULL_DATA | cut -d ":" -f 5) #This gives values as 2.10.0 OR 2.40
if [ $VERSION -gt $REQUIRED_VERSION ]]
then
echo "=== PASSED ==== "
else
echo "=== FAILED ==="
#exit 1
fi
使用 zsh 出现如下错误
test.sh:60:浮点常数错误
它总是给出与 sh 传递的结果
我也尝试过 bc 但不起作用,可能缺少语法不确定。
请建议一些从字符串类型转换为浮点数的方法,我可以进一步与shell或zsh进行比较
答:
2赞
Ed Morton
7/26/2023
#1
您不能将版本作为任何类型的数字(包括浮点数)进行比较,也不能作为字符串进行比较,因为每个分隔的部分都需要单独进行数字比较。您需要专门将它们作为版本进行比较,例如使用 GNU sort for 将版本号列表按从低到高的顺序排序:.
-V
$ cat tst.sh
#!/usr/bin/env bash
required_version=2.38.0
actual_version=10.7.45
highest_version=$(printf '%s\n%s\n' "$required_version" "$actual_version" | sort -V | tail -1)
if [[ $highest_version == $actual_version ]]; then
echo "=== PASSED ==="
else
echo "=== FAILED ==="
fi
$ ./tst.sh
=== PASSED ===
如果你没有GNU,你可以随时编写自己的比较函数,例如:sort
$ cat tst.sh
#!/usr/bin/env bash
required_version=2.38.0
actual_version=10.7.45
compare_vers() {
local a b n
IFS='.' read -r -a a <<< "$1"
IFS='.' read -r -a b <<< "$2"
(( "${#a[@]}" > "${#b[@]}" )) && n="${#a[@]}" || n="${#b[@]}"
for (( i=0; i<n; i++ )); do
if (( "${a[i]:0}" > "${b[i]:0}" )); then
echo 'BIGGER'
return
elif (( "${a[i]:0}" < "${b[i]:0}" )); then
echo 'SMALLER'
return
fi
done
echo 'EQUAL'
}
rslt=$(compare_vers "$actual_version" "$required_version")
if [[ $rslt == "BIGGER" ]]; then
echo "=== PASSED ==="
else
echo "=== FAILED ==="
fi
$ ./tst.sh
=== PASSED ===
评论
0赞
Shubham Jain
7/26/2023
那是工作 ED ..谢谢。。还有一个小疑问,如何在if语句中做大于和等于...对我来说,如果[[ $highest_version > $actual_version ]];有效但不>=
0赞
Shubham Jain
7/26/2023
我正在尝试这个->。如果 [[ $highest_version>$actual_version && $highest_version=$actual_version ]];->当它们也相等时它会失败,知道为什么吗?
0赞
Ed Morton
7/26/2023
With,或者您仍在尝试将版本作为字符串或数字进行比较。正如我所提到的,你不能这样做,因为版本不是一个数字(除非它只包含 1 ),所以版本不能用数字来比较,也不能像字符串比较那样按字母顺序逐个字符地比较它们。如果你告诉我你想做什么(而不是告诉我你是如何尝试的),我可以帮忙。>
>=
.
3赞
Eric Postpischil
7/26/2023
#2
版本号不是数学数字。Bash 没有内置的方法来比较版本号。该命令用于比较版本号和报告文件是否正确排序。你可以将其与 Bash 的功能一起使用,将即时输入传递给命令:sort
-V
-C
<<<
#!/bin/bash -e
A="2.38.0"
B="2.3.1"
if sort -C -V <<<"$A"$'\n'"$B"; then
echo "A is earlier than or the same as B."
else
echo "A is later than B."
fi
该语法是用于生成换行符的 Bash 功能。$'\n'
Bash 允许您在命令之前使用 a 否定测试:!
if ! sort -C -V <<<"$A"$'\n'"$B"; then
请注意,将报告“2.38”早于“2.38.0”。sort
1赞
glenn jackman
7/26/2023
#3
这可以在纯 bash 中完成,但当然它需要更多的代码:
required_version=2.38.0
ver2float() {
local parts part frac=""
IFS=. read -ra parts <<<"$1"
for part in "${parts[@]:1}"; do
frac+=$(printf "%03d" "$part")
done
printf "%s.%s" "${parts[0]}" "${frac:-0}"
}
compare_floats() {
(( 10#${1%.*} > 10#${2%.*} )) && return 1
(( 10#${1%.*} < 10#${2%.*} )) && return 0
(( 10#${1#*.} <= 10#${2#*.} ))
}
for version in 1.0 2.37.99 2.38.0 2.38.1 12; do
if compare_floats "$(ver2float "$required_version")" \
"$(ver2float "$version")"
then
echo "$required_version is less than or equal to $version"
else
echo "$required_version is greater than $version"
fi
done
这输出
2.38.0 is greater than 1.0
2.38.0 is greater than 2.37.99
2.38.0 is less than or equal to 2.38.0
2.38.0 is less than or equal to 2.38.1
2.38.0 is less than or equal to 12
1赞
Gairfowl
7/27/2023
#4
zsh
附带一个比较版本号的功能:
autoload is-at-least
is-a-least 2.38 2.0
print $?
# => 1
它可以接受点或破折号作为分隔符,看起来它也可以处理字母:
#!/usr/bin/env zsh
autoload is-at-least
tstVer(){
local m=nope
is-at-least ${1:?} ${2:?} && m=WORKS
printf 'need: %-6s have: %-6s %s\n' $1 $2 $m
}
tstVer 0.3 1.0
tstVer 3 4.3-33
tstVer 4.4 4.3-33
tstVer 2.3d 2.3c
tstVer 5.3.0 5.3
tstVer 5.3 5.3.0
# => need: 0.3 have: 1.0 WORKS
# => need: 3 have: 4.3-33 WORKS
# => need: 4.4 have: 4.3-33 nope
# => need: 2.3d have: 2.3c nope
# => need: 5.3.0 have: 5.3 WORKS
# => need: 5.3 have: 5.3.0 WORKS
评论
bash
仅支持整数数学运算。并且会给确实具有浮点数的工具带来问题。3.28.0
sort -V