在Shell脚本中比较整数和浮点数的区别

6

在shell脚本中,我们如何使用一个if条件语句来比较整数、浮点数、浮点数与浮点数、浮点数与整数以及整数与整数。

我有一些例子:

 set X=3.1
  set Y=4.1
  if [ $X < $Y ] then
    echo "wassup"
  endif

但是在定时任务中运行上述命令似乎不起作用。


可能是重复的问题,参考Bash:Integer expression expected - tripleee
4个回答

19

在Bash中进行浮点数运算的方法是使用bc,这个工具在几乎所有Linux发行版上都可用。

# bc will return 0 for false and 1 for true
if [ $(echo "23.3 > 7.3" | bc) -ne 0 ] 
then 
  echo "wassup"
fi

在 Linux Journal 上有一篇关于使用 bc 在 bash 中进行浮点数计算的好文章


1
我尝试了以下操作,但出现了错误,提示需要一元运算符。 - Rajeev
有趣。我在这里已经成功运行了。嗯,你的错误意味着(我想)$(echo "$a > $b" | bc)没有返回值。你能试试子shell吗? - brice
你的变量没有正确赋值。例如,echo $X 将会输出一个空行。 - brice

1

Bah本身只处理整数。请使用bc:

echo "$X>$Y" | bc 
0
echo "$X<$Y" | bc 
1

您不需要担心规模。这仅仅是输出格式的精度问题:

X=3.000001
Y=3.0001
echo "$X>$Y" | bc 
0
echo "$X<$Y" | bc 
1
echo "scale=1;$X<$Y" | bc 
1

0

以下示例适用于Bash Shell。

 X=3.1
 Y=4.1
 if [ $X -le $Y ]
 then
    echo "wassup"
 fi

你可能想要学习Shell脚本在这里


3
这里不起作用,因为bash无法处理浮点数: $ test "34.4" -gt "5.4" -> bash: test: 34.4: integer expression expected - brice
5
我不怀疑你的真诚 :) 我只是想说这并不能保证在Linux上运行。bash --version 告诉我 GNU bash, version 4.2.8(1)-release (x86_64-pc-linux-gnu) - brice

0

根据这个答案的评论(感谢user unknownglenn jackman),似乎在使用bc进行true/false测试时,所需的bash测试仅为:

  • (( $(echo "$X < $Y" |bc) )) ... 请参见下面的测试结果和脚本

而对于旧式bash [ ]测试,则需要与-ne 0进行比较。


bash 本身不支持浮点数,但是你可以调用像 bc 这样的工具。

man bc 中得知,它是一种任意精度计算器语言。

X=3.1
Y=4.1
# This test has two superfluous components. 
# See EDIT (above) and TESTS below
if (($(echo "scale=9; $X < $Y" |bc)!=0)) ;then
    echo "wassup"
fi

测试结果:

if [  "1"  ]   true
   [  "1"  ]   true
if [  "0"  ]   true
   [  "0"  ]   true

if [   1   ]   true
   [   1   ]   true
if [   0   ]   true
   [   0   ]   true

if (( "1" ))   true
   (( "1" ))   true
if (( "0" ))   false
   (( "0" ))   false

if ((  1  ))   true
   ((  1  ))   true
if ((  0  ))   false
   ((  0  ))   false

echo "1<1"|bc  true
echo "1<0"|bc  true

测试脚本:

printf 'if [  "1"  ]   '; if [ "1" ]; then echo true; else echo false; fi
printf '   [  "1"  ]   ';    [ "1" ]  &&   echo true  ||   echo false
printf 'if [  "0"  ]   '; if [ "0" ]; then echo true; else echo false; fi
printf '   [  "0"  ]   ';    [ "0" ]  &&   echo true  ||   echo false
echo  
printf 'if [   1   ]   '; if [  1  ]; then echo true; else echo false; fi
printf '   [   1   ]   ';    [  1  ]  &&   echo true  ||   echo false
printf 'if [   0   ]   '; if [  0  ]; then echo true; else echo false; fi
printf '   [   0   ]   ';    [  0  ]  &&   echo true  ||   echo false
echo  
printf 'if (( "1" ))   '; if (("1")); then echo true; else echo false; fi
printf '   (( "1" ))   ';    (("1"))  &&   echo true  ||   echo false
printf 'if (( "0" ))   '; if (("0")); then echo true; else echo false; fi
printf '   (( "0" ))   ';    (("0"))  &&   echo true  ||   echo false
echo  
printf 'if ((  1  ))   '; if (( 1 )); then echo true; else echo false; fi
printf '   ((  1  ))   ';    (( 1 ))  &&   echo true  ||   echo false
printf 'if ((  0  ))   '; if (( 0 )); then echo true; else echo false; fi
printf '   ((  0  ))   ';    (( 0 ))  &&   echo true  ||   echo false
echo
printf 'echo "1<1"|bc  '; echo "1<1"|bc >/dev/null  && echo true || echo false 
printf 'echo "1<0"|bc  '; echo "1<0"|bc >/dev/null  && echo true || echo false 

1
如果你只是想测试真和假,那么“scale”是多余的。 “!= 0”也是多余的 - 这已经完成了。 - user unknown
1
!=0 不是多余的:因为 bc 会打印出 false 或 true 的 0 或 1。在这两种情况下,退出状态 都是零。因此,你必须将命令输出与某些内容进行比较。 - glenn jackman
1
好的想法,但是有误:if (($(echo "$X > $Y" | bc))) ; then echo wassup; else echo pussaw; fi。原因:$(...) 捕获输出。((...)) 评估。 - user unknown
看起来你们两个都是对的,只是针对不同的格式 :) ... 我已经在我的答案中添加了测试。 - Peter.O
@glennjackman:我忘记为你打通知标记了。抱歉。 - user unknown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接