如何比较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将打印1或0 ,那些将被if子句用true或false解释 。
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