我正在努力比较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的正确处理存在一些问题,这可能是“电子格式”。 :(
欢迎任何帮助,提示!
答案 0 :(得分:116)
使用Bash的数字上下文可以更方便地完成此操作:
if (( $(echo "$num1 > $num2" |bc -l) )); then
…
fi
通过基本计算器命令bc
进行管道返回1或0。
选项-l
相当于--mathlib
;它加载标准数学库。
将整个表达式括在双括号(( ))
之间会将这些值分别转换为真或假。
请确保已安装bc
基本计算器软件包。
这同样适用于科学格式的花车,只要使用大写字母E
,例如num1=3.44E6
答案 1 :(得分:96)
bash只处理整数数学
但您可以按如下方式使用bc
命令:
$ num1=3.17648E-22
$ num2=1.5
$ echo $num1'>'$num2 | bc -l
0
$ echo $num2'>'$num1 | bc -l
1
请注意,指数符号必须为大写
答案 2 :(得分:23)
最好将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
答案 3 :(得分:20)
用于比较没有指数表示法,前导或尾随零的浮点数的纯bash解决方案:
if [ ${FOO%.*} -eq ${BAR%.*} ] && [ ${FOO#*.} \> ${BAR#*.} ] || [ ${FOO%.*} -gt ${BAR%.*} ]; then
echo "${FOO} > ${BAR}";
else
echo "${FOO} <= ${BAR}";
fi
逻辑运算符的顺序matters。将整数部分作为数字进行比较,将小数部分有意地作为字符串进行比较。使用this method将变量分为整数和小数部分。
不会将浮点数与整数(没有点数)进行比较。
答案 4 :(得分:10)
你可以使用awk和bash结合条件,awk将打印 1 或 0 ,这些将由if子句解释为 true 或 false 。
if (( $(awk 'BEGIN {print ("'$d1'" >= "'$d2'")}') )); then
echo "yes"
else
echo "no"
fi
答案 5 :(得分:5)
在比较包版本的数字时要小心,比如检查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
答案 6 :(得分:3)
我使用了这里的答案并将它们放在一个函数中,你可以像这样使用它:
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
答案 7 :(得分:3)
当然,如果你不需要真正的浮点运算,那么只需算术运算,例如美元值总是正好有两位小数,你可能只是放下点(有效地乘以100)并比较得到的整数。
if [[ $((10#${num1/.})) < $((10#${num2/.})) ]]; then
...
这显然要求您确保两个值具有相同的小数位数。
答案 8 :(得分:2)
此脚本可能有助于我检查安装的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
答案 9 :(得分:1)
awk
和类似的工具(我正盯着你sed
...)应该降级到旧项目的垃圾箱,代码是每个人都不敢触摸,因为它是用永不言喻的语言写成。
或者你是一个相对稀少的项目,需要优先考虑CPU使用优化而不是代码维护优化......在这种情况下,继续进行。
如果没有,为什么不使用可读和明确的东西,例如python
?你的编码员和未来的自我会感谢你。你可以像其他所有人一样使用python
内联bash。
num1=3.17648E-22
num2=1.5
if python -c "import sys; sys.exit(0 if float($num1) < float($num2) else 1)"; then
echo "yes, $num1 < $num2"
else
echo "no, $num1 >= $num2"
fi
答案 10 :(得分:1)
请检查下面的编辑代码:-
#!/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
这很好。
答案 11 :(得分:1)
使用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混合提供了更多...
答案 12 :(得分:1)
使用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
答案 13 :(得分:0)
这个怎么样? = 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
答案 14 :(得分:0)
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
答案 15 :(得分:0)
同时支持大写和小写指数(例如12.00e4
)的科学计数法的解决方案:
if (( $(bc -l <<< "${value1/e/E} < ${value2/e/E}") ))
then
echo "$value1 is less than $value2"
fi
答案 16 :(得分:0)
我将其发布为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...
答案 17 :(得分:0)
只需用 printf 替换 echo
(它理解浮点数):
st=$( printf '%50G < %50G\n' "$num1" "$num2" | bc -l )