我正在努力比较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,可以是“电子格式”。

评论

“电子格式”是指指数符号(也称为科学符号)

相关:UNIX Shell脚本中的浮点运算

#1 楼

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

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


解释

通过基本计算器命令bc返回1或0。

选项-l等效于--mathlib;它会加载标准数学库。

将整个表达式括在双括号(( ))之间会将这些值分别转换为true或false。

请确保bc基本计算器包已安装。

如果使用大写字母E,则这同样适用于科学格式的浮标,例如num1=3.44E6

评论


与stackoverflow.com/questions/8654051/…相同的问题,例如$ echo“ 1.1 + 2e + 02” | bc(standard_in)1:语法错误

– Nemo
16-2-2在10:55



@MohitArora请确保您已安装bc计算器包。

– Serge Stroobandt
17 Mar 28 '17在18:52



我得到一个0:在语句if(($(echo“ $ TOP_PROCESS_PERCENTAGE> $ THRESHOLD” | bc -l))中找不到);然后。

– Stephane
17年8月4日在13:14

对于所有获得“未找到命令”的用户,请记住,您需要将bc放入反引号或$()中,然后放入(())... ...((($(bc -l <​​<<“ $ a> $ b“)))而不是((bc -l <​​<<” $ a> $ b“))。

–标准化
18年4月13日在1:13



@Nemo以科学计数法用大写字母E书写数字,所有语法错误都将消失。

– Serge Stroobandt
19年5月19日在7:35

#2 楼

bash仅处理整数数学
,但您可以按以下方式使用bc命令:

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


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

评论


是的,但是要解决错误的计算,需要使用大写字母“ e”以科学数字符号表示,并使用-l标志对bc编程以进行预定义的数学例程

– alrusdi
2011-12-28 10:24



然后,您应该在答案中指出这一点,而不是仅仅发布一个非常相似的解决方案,而不要提及重要的差异。

–丹尼尔·佩尔森(Daniel Persson)
2011-12-28 10:34

这不是一个非常相似的解决方案。 Alrusdi的解决方案使用了bc工具,这就是我向任何BASH程序员推荐的方法。 BASH是无类型语言。是的,它可以执行整数运算,但是对于浮点数,您必须使用一些外部工具。 BC是最好的,因为这就是它的目的。

– DejanLekic
2011-12-28 14:42

因为他试图在if语句中使用它,所以我会证明这一点。如果[$(... | bc -l)== 1];然后 ...

–罗伯特·雅各布斯
15年3月3日在22:12

#3 楼

最好对非整数数学使用awk。您可以使用以下bash实用程序功能:

numCompare() {
   awk -v n1="" -v n2="" '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 esp初学者,他们似乎认为比实际困难得多,我认为人们被花括号和看似语言混合的语法所吓倒。而且由于几乎可以保证awk也将出现在目标系统上,就像bc一样(不确定是否安装了哪一个)。我喜欢bash脚本,但是没有浮点数,甚至没有微不足道的2个小数位(我猜有人可以为此写一个“假”包装器),真的很烦人...

– osirisgothra
13年11月6日在11:03

自古以来,在shell脚本中使用awk和bc是一种标准做法,我想说一些功能从未添加到shell中,因为它们在awk,bc和其他Unix工具中可用。 Shell脚本中无需纯洁。

– Piokuc
2014年9月15日上午10:06

@WanderingMind这样做的一种方法是传递0或1退出,以便Awk以正确的,机器可读的方式将结果传递回Shell。如果awk -v n1 =“ 123.456” -v n2 =“ 3.14159e17”'BEGIN {退出(n1 <= n2)}'/ dev / null;然后回声更大;否则不回声; fi ...尽管请注意条件是如何反转的(退出状态0表示shell成功)。

–tripleee
16年8月12日在5:13



人们在考虑这个答案,请帮自己一个忙,不要打扰awk。如果您认为awk是答案,请直接使用内嵌python来完成。您的同事和未来的自我将感谢您。

– CivFan
17年7月19日在14:56



为什么只是python。默认情况下,您已经在许多Linux / Unix系统上安装了perl。

– anubhava
17年7月19日在15:44

#4 楼

用于比较没有指数符号,前导或尾随零的浮点数的纯bash解决方案:

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


逻辑运算符的顺序很重要。将整数部分作为数字进行比较,并将小数部分作为字符串进行有意比较。使用此方法将变量分为整数部分和小数部分。

不会将浮点数与整数(不带点)进行比较。

#5 楼

如果满足以下条件,则可以将awk与bash结合使用:
if awk 'BEGIN {exit !('$d1' >= '$d2')}'; then
    echo "yes"
else 
    echo "no"
fi


评论


使用awk很棒,因为它可以处理浮点数,但是我个人更喜欢synthax if(($(echo $ d1 $ d2 | awk'{if($ 1> $ 2)print 1;}')))));;然后回声“是”;否则回声“否”;科幻

–David Georg Reichelt
7月13日13:04

该功能无法正常运行。无论如何,Awk都以0状态退出。用exit替换print,就可以了。

–奥修斯
8月28日14:40

@Otheus您需要用exit!替换它,否则它将返回相反的结果。我适当地编辑了答案。

– mgutt
10月13日21:47

#6 楼

当比较软件包版本号时要当心,例如检查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="" operator="" value="" 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


评论


在基于Debian的系统上,dpkg --compare-versions通常很有用。它具有比较内置的Debian软件包版本的完整逻辑,这不仅比x.y还复杂。

–尼尔·梅休(Neil Mayhew)
17年12月14日在21:10

#7 楼

当然,如果您不需要真正的浮点算术,只需在美元的值始终总是恰好有两个十进制数字,您可以删除点(有效乘以100)并比较所得的整数。

if [[ $((10#${num1/.})) < $((10#${num2/.})) ]]; then
    ...


这显然需要您确保两个值的小数位数相同。

#8 楼

我从这里使用了答案并将其放在函数中,可以像这样使用它: 。

功能:

is_first_floating_number_bigger 1.5 1.2
result="${__FUNCTION_RETURN}"


或带有调试输出的版本:

is_first_floating_number_bigger () {
    number1=""
    number2=""

    [ ${number1%.*} -eq ${number2%.*} ] && [ ${number1#*.} \> ${number2#*.} ] || [ ${number1%.*} -gt ${number2%.*} ];
    result=$?
    if [ "$result" -eq 0 ]; then result=1; else result=0; fi

    __FUNCTION_RETURN="${result}"
}


只需将函数保存在单独的echo $result文件中,然后像这样包含它:

is_first_floating_number_bigger () {
    number1=""
    number2=""

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


#9 楼

请检查以下经过编辑的代码:-

#!/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


这很好。

#10 楼

我将其发布为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...


评论


@DudiBoy不,它是清晰,简单,可移植的awk代码,或者是非显而易见的,晦涩的,与外壳相关的shell + bc代码。

–埃德·莫顿(Ed Morton)
19年6月2日在16:53

#11 楼

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


评论


@Witiko我的原始版本有点奇怪。

– CivFan
17-10-16在15:39



更简洁:如果...否则,请使用not(...)而不是0

–尼尔·梅休(Neil Mayhew)
17年12月14日在21:06

如果您将awk和sed(我在看您的CivFan)降级为历史的垃圾箱,则您是糟糕的系统管理员,并且您输入的代码太多。 (而且我喜欢并使用Python,因此并非如此)。 -1用于放错位置的贪睡。在系统领域中,对于那些工具(Python或否)有一个地方。

– Mike S
17年12月14日在21:42

有趣的是,我最终获得了出色的ol'Perl! awk'$ {print $ 5}'ptpd_log_file | perl -ne'$ _> 0.000100 &&打印'> / tmp / outfile。十分简单。每种语言都有其位置。

– Mike S
17年12月14日在22:22

不要让seds语法古怪。与python不同,awk是每个UNIX安装上的强制性实用程序,并且python -c“ import sys; sys.exit(0如果float($ num1) $ num2?0:1)}”。

–埃德·莫顿(Ed Morton)
19年6月2日14:40



#12 楼

一种支持所有可能的表示法的解决方案,包括具有大写和小写指数的科学表示法(例如12.00e4):

 if (( $(bc -l <<< "${value1/e/E} < ${value2/e/E}") ))
then
    echo "$value1 is below $value2"
fi 
 


#13 楼

该脚本可能会在我检查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


#14 楼

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 楼

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


评论


问题是许多发行版都没有安装ksh,并且如果您的脚本将被其他人使用,则它们倾向于不喜欢安装额外的内容,尤其是当它只是应该以bash编写的脚本时-会认为他们不需要另一个shell来执行此操作,这首先破坏了使用bash脚本的全部原因-确保我们也可以在C ++中对其进行编码,但是为什么?

– osirisgothra
13年11月6日上午10:56

没有安装ksh的发行版有哪些?

– Piokuc
2014年9月15日上午10:01

@piokuc,例如Ubuntu Desktop&Server。我会说这是一个很重要的...

–奥利
2014年12月21日上午11:57

另外,问题专门要求在bash中有效的解决方案。可能确实有很好的理由。说,这是大型应用程序的一部分,将所有内容迁移到ksh是不可行的。或者它正在嵌入式平台上运行,而在该平台上确实要安装另一个shell。

–奥利
2014年12月21日12:00

#16 楼

使用具有Java支持的bash突变体bashj(https://sourceforge.net/projects/bashj/),您只需编写(而且易于阅读):

#!/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混合提供了更多...

#17 楼

这个怎么样? = D

VAL_TO_CHECK="1.00001"
if [ $(awk '{printf( >= ) ? 1 : 0}' <<<" $VAL_TO_CHECK 1 ") -eq 1 ] ; then
    echo "$VAL_TO_CHECK >= 1"
else
    echo "$VAL_TO_CHECK < 1"
fi


评论


Awk脚本应该简单地退出0来报告真相,退出1来返回false。那么如果awk'BEGIN {exit(ARGV [1]> = ARGV [2])吗? 0:1}'“ $ VAL_TO_CHECK” 1;然后...(如果将Awk脚本封装在shell函数中,则更加优雅)。

–tripleee
17 Dec 8'在10:45