![](/img/trans.png)
[英]How to search numbers after decimal point for floating point number in Bash?
[英]How to compare two floating point numbers in Bash?
我正在努力比较 bash 脚本中的两个浮点数。 我必须变量,例如
let num1=3.17648e-22
let num2=1.5
现在,我只想对这两个数字做一个简单的比较:
st=`echo "$num1 < $num2" | bc`
if [ $st -eq 1]; then
echo -e "$num1 < $num2"
else
echo -e "$num1 >= $num2"
fi
不幸的是,我对 num1 的正确处理有一些问题,它可能是“电子格式”。
这可以使用 Bash 的数字上下文更方便地完成:
if (( $(echo "$num1 > $num2" |bc -l) )); then
…
fi
通过基本计算器命令bc
管道返回 1 或 0。
选项-l
等效于--mathlib
; 它加载标准数学库。
将整个表达式括在双括号(( ))
会将这些值分别转换为 true 或 false。
请确保安装了bc
基本计算器包。
警告:指数符号应写为*10^
; 不是E
,也不是e
。
例如:
$ echo '1*10^3==1000" |bc
1
然而
$ echo '1E3==1000" |bc
0
此处讨论了克服此bc
限制的策略。
bash 仅处理整数数学,但您可以使用bc
命令,如下所示:
$ num1=3.17648E-22
$ num2=1.5
$ echo $num1'>'$num2 | bc -l
0
$ echo $num2'>'$num1 | bc -l
1
注意指数符号必须大写
最好将awk
用于非整数数学。 您可以使用此 bash 实用程序功能:
numCompare() {
awk -v n1="$1" -v n2="$2" 'BEGIN {printf "%s " (n1<n2?"<":">=") " %s\n", n1, n2}'
}
并将其称为:
numCompare 5.65 3.14e-22
5.65 >= 3.14e-22
numCompare 5.65e-23 3.14e-22
5.65e-23 < 3.14e-22
numCompare 3.145678 3.145679
3.145678 < 3.145679
如果条件满足,您可以将awk
与 bash 结合使用:
if awk "BEGIN {exit !($d1 >= $d2)}"; then
echo "yes"
else
echo "no"
fi
比较软件包版本的数字时要小心,例如检查 grep 2.20 是否大于版本 2.6:
$ awk 'BEGIN { print (2.20 >= 2.6) ? "YES" : "NO" }'
NO
$ awk 'BEGIN { print (2.2 >= 2.6) ? "YES" : "NO" }'
NO
$ awk 'BEGIN { print (2.60 == 2.6) ? "YES" : "NO" }'
YES
我用这样的 shell/awk 函数解决了这个问题:
# get version of GNU tool
toolversion() {
local prog="$1" operator="$2" value="$3" version
version=$($prog --version | awk '{print $NF; exit}')
awk -vv1="$version" -vv2="$value" 'BEGIN {
split(v1, a, /\./); split(v2, b, /\./);
if (a[1] == b[1]) {
exit (a[2] '$operator' b[2]) ? 0 : 1
}
else {
exit (a[1] '$operator' b[1]) ? 0 : 1
}
}'
}
if toolversion grep '>=' 2.6; then
# do something awesome
fi
当然,如果您不需要真正的浮点算术,只需对美元值进行算术运算,其中始终只有两位十进制数字,您可能只需删除点(有效乘以 100)并比较结果整数。
if [[ $((10#${num1/.})) < $((10#${num2/.})) ]]; then
...
这显然要求您确保两个值具有相同的小数位数。
awk
和类似的工具(我在盯着你sed
...)应该被归入旧项目的垃圾箱,因为它的代码是用永不阅读的语言编写的,所以每个人都不敢碰它。
或者您是需要优先考虑 CPU 使用优化而不是代码维护优化的相对罕见的项目……在这种情况下,继续。
如果没有,为什么不使用可读和明确的东西,比如python
? 你的程序员伙伴和未来的自己会感谢你。 您可以像所有其他人一样将python
与 bash 内联使用。
num1=3.17648E-22
num2=1.5
if python -c "exit(0 if $num1 < $num2 else 1)"; then
echo "yes, $num1 < $num2"
else
echo "no, $num1 >= $num2"
fi
支持所有可能的符号的解决方案,包括具有大写和小写指数的科学记数法(例如, 12.00e4
):
if (( $(bc -l <<< "${value1/e/E} < ${value2/e/E}") ))
then
echo "$value1 is below $value2"
fi
我使用了这里的答案并将它们放在一个函数中,你可以这样使用它:
is_first_floating_number_bigger 1.5 1.2
result="${__FUNCTION_RETURN}"
一旦调用,在这种情况下echo $result
将为1
,否则为0
。
功能:
is_first_floating_number_bigger () {
number1="$1"
number2="$2"
[ ${number1%.*} -eq ${number2%.*} ] && [ ${number1#*.} \> ${number2#*.} ] || [ ${number1%.*} -gt ${number2%.*} ];
result=$?
if [ "$result" -eq 0 ]; then result=1; else result=0; fi
__FUNCTION_RETURN="${result}"
}
或带有调试输出的版本:
is_first_floating_number_bigger () {
number1="$1"
number2="$2"
echo "... is_first_floating_number_bigger: comparing ${number1} with ${number2} (to check if the first one is bigger)"
[ ${number1%.*} -eq ${number2%.*} ] && [ ${number1#*.} \> ${number2#*.} ] || [ ${number1%.*} -gt ${number2%.*} ];
result=$?
if [ "$result" -eq 0 ]; then result=1; else result=0; fi
echo "... is_first_floating_number_bigger: result is: ${result}"
if [ "$result" -eq 0 ]; then
echo "... is_first_floating_number_bigger: ${number1} is not bigger than ${number2}"
else
echo "... is_first_floating_number_bigger: ${number1} is bigger than ${number2}"
fi
__FUNCTION_RETURN="${result}"
}
只需将函数保存在一个单独的.sh
文件中,并像这样包含它:
. /path/to/the/new-file.sh
请检查以下编辑过的代码:-
#!/bin/bash
export num1=(3.17648*e-22)
export num2=1.5
st=$((`echo "$num1 < $num2"| bc`))
if [ $st -eq 1 ]
then
echo -e "$num1 < $num2"
else
echo -e "$num1 >= $num2"
fi
这很好用。
当它作为此问题的副本关闭时,我将其发布为https://stackoverflow.com/a/56415379/1745001的答案,因此这里也适用:
为简单起见,只需使用 awk 进行计算,因为它是标准的 UNIX 工具,因此与 bc 一样可能出现,并且在语法上更易于使用。
对于这个问题:
$ cat tst.sh
#!/bin/bash
num1=3.17648e-22
num2=1.5
awk -v num1="$num1" -v num2="$num2" '
BEGIN {
print "num1", (num1 < num2 ? "<" : ">="), "num2"
}
'
$ ./tst.sh
num1 < num2
对于另一个问题,作为这个问题的重复而结束:
$ cat tst.sh
#!/bin/bash
read -p "Operator: " operator
read -p "First number: " ch1
read -p "Second number: " ch2
awk -v ch1="$ch1" -v ch2="$ch2" -v op="$operator" '
BEGIN {
if ( ( op == "/" ) && ( ch2 == 0 ) ) {
print "Nope..."
}
else {
print ch1 '"$operator"' ch2
}
}
'
$ ./tst.sh
Operator: /
First number: 4.5
Second number: 2
2.25
$ ./tst.sh
Operator: /
First number: 4.5
Second number: 0
Nope...
这个脚本可以帮助我检查安装的grails
版本是否大于最低要求。 希望能帮助到你。
#!/bin/bash
min=1.4
current=`echo $(grails --version | head -n 2 | awk '{print $NF}' | cut -c 1-3)`
if [ 1 -eq `echo "${current} < ${min}" | bc` ]
then
echo "yo, you have older version of grails."
else
echo "Hurray, you have the latest version"
fi
num1=0.555
num2=2.555
if [ `echo "$num1>$num2"|bc` -eq 1 ]; then
echo "$num1 is greater then $num2"
else
echo "$num2 is greater then $num1"
fi
使用 korn shell,在 bash 中,您可能需要分别比较小数部分
#!/bin/ksh
X=0.2
Y=0.2
echo $X
echo $Y
if [[ $X -lt $Y ]]
then
echo "X is less than Y"
elif [[ $X -gt $Y ]]
then
echo "X is greater than Y"
elif [[ $X -eq $Y ]]
then
echo "X is equal to Y"
fi
这个怎么样? =D
VAL_TO_CHECK="1.00001"
if [ $(awk '{printf($1 >= $2) ? 1 : 0}' <<<" $VAL_TO_CHECK 1 ") -eq 1 ] ; then
echo "$VAL_TO_CHECK >= 1"
else
echo "$VAL_TO_CHECK < 1"
fi
使用 bashj ( https://sourceforge.net/projects/bashj/ ),一个支持 java 的 bash 突变体,你只需编写(并且很容易阅读):
#!/usr/bin/bashj
#!java
static int doubleCompare(double a,double b) {return((a>b) ? 1 : (a<b) ? -1 : 0);}
#!bashj
num1=3.17648e-22
num2=1.5
comp=j.doubleCompare($num1,$num2)
if [ $comp == 0 ] ; then echo "Equal" ; fi
if [ $comp == 1 ] ; then echo "$num1 > $num2" ; fi
if [ $comp == -1 ] ; then echo "$num2 > $num1" ; fi
当然 bashj bash/java 混合提供了更多......
只需用 printf 替换echo
(它理解浮点数):
st=$( printf '%50G < %50G\n' "$num1" "$num2" | bc -l )
有一种简单的方法,它比 AWK 快一点,并且不需要安装bc
。 它利用sort
对浮点数进行排序的能力:
A=1280.4
B=9.325
LOW=$(sort -n <<< "$A"$'\n'"$B" | head -1)
if [[ "$LOW" == "$A" ]]; then
echo "A <= B"
else
echo "A >= B"
fi
当然,它不适用于相等的数字。
一个班轮解决方案
假设你有两个变量A
和B
echo "($A > $B) * $B + ($A < $B) * $A" | bc
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.