如何比较Bash中的两个浮点数?

我正在努力比较一个bash脚本中的两个浮点数。 我必须variables,例如

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只处理整数math,但你可以使用bc命令如下:

 $ num1=3.17648E-22 $ num2=1.5 $ echo $num1'>'$num2 | bc -l 0 $ echo $num2'>'$num1 | bc -l 1 

请注意,指数符号必须是大写的

更方便

这可以使用Bash的数字上下文更方便地完成:

 if (( $(echo "$num1 > $num2" |bc -l) )); then … fi 

说明:

bc返回1或0,并将整个expression式用双括号(( ))括起来,将这些值分别转换为true或false。

请确保安装了bc计算器软件包。

awk用于非整数math更好。 你可以使用这个bash实用程序function:

 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 

纯粹的bash解决scheme比较没有指数表示法的浮点数,前导或尾随零点:

 if [ ${FOO%.*} -eq ${BAR%.*} ] && [ ${FOO#*.} \> ${BAR#*.} ] || [ ${FOO%.*} -gt ${BAR%.*} ]; then echo "${FOO} > ${BAR}"; else echo "${FOO} <= ${BAR}"; fi 

逻辑运算符的顺序很重要 。 整数部分作为数字进行比较,小数部分作为string进行故意比较。 variables被分成整数和小数部分使用这种方法 。

不会比较浮点数与整数(没有点)。

你可以使用awk与bash结合使用,如果条件,awk将打印10 ,那些将被if子句用truefalse解释

 if (( $(awk 'BEGIN {print ("'$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 

我用这里的答案把它们放在一个函数中,你可以像这样使用它:

 is_first_floating_number_bigger 1.5 1.2 result="${__FUNCTION_RETURN}" 

一旦调用,在这种情况下, echo $result将是1 ,否则为0

function:

 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}" } 

或者带有debugging输出的版本:

 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 

使用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 

这个脚本可能会帮助我检查安装的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 "Bro, you have older version of grails." else echo "Hurray, you have the latest version" 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 

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