我可以在bash脚本中使用分数/小数吗?

在bash脚本中使用分数或小数时是否需要使用某种语法?

我尝试使用以下脚本(在Ubuntu 12.04中):

#!/bin/bash { n=9 echo "$n" for (( i=.5; $i <10; i++ )); do let "c=$i+1" echo $i "+" $c done } 

这适用于i=1 ,但是当我输入.5时会产生语法错误。

是的bash只处理整数,但你可以绕过这个问题,不是使用bash(Python很容易拿起)或者使用bc来处理计算。

请记住,你的for循环中的条件不适用于分数,所以你也需要扩展它。

 step="0.5" for (( i=0; $i<$(bc<<<"10/$step"); i++ )); do echo $(bc<<<"$step * $i") done 

这将以0.5增量回显09.5

你可以使用Zsh 。

大多数shell,包括Bash,都不直接支持浮点计算 , 正如Oli所解释的那样 ,典型的解决方法是调用bc 。 但是, 您有许多其他选择 。

其中之一是使用Z Shellzsh是一个Bourne风格的shell ( 与 Bash 相同的“系列” )直接支持浮点计算。 因此,如果您愿意将其设置为Zsh脚本而不是Bash脚本,则可以通过将脚本的第一行从#!/bin/bash更改为#!/bin/zsh

一旦你这样做,它将自动工作! 在这种情况下 ,不需要对脚本进行进一步修改。 (有时,Bashfunction和相应的Zshfunction的工作方式不同,因此将脚本从Bash转换为Zsh需要您进行更改。虽然有时候带有错误的Bash脚本在被视为Zsh脚本时实际上可能会变得正确,但由于不同在Zsh中设计应该自动执行哪些扩展的 决策 。)

这是输出:

 9 0.5000000000 + 1.5000000000 1.5000000000 + 2.5000000000 2.5000000000 + 3.5000000000 3.5000000000 + 4.5000000000 4.5000000000 + 5.5000000000 5.5000000000 + 6.5000000000 6.5000000000 + 7.5000000000 7.5000000000 + 8.5000000000 8.5000000000 + 9.5000000000 9.5000000000 + 10.5000000000 

您需要安装Zsh才能运行它。 Zsh通常不会预装在Ubuntu上,但它是由zsh包提供的。 如果您没有zsh那么您将看到如下错误:

 -bash: ./your-script : /bin/zsh: bad interpreter: No such file or directory 

Ubuntu的zsh包为你提供/bin/zsh/usr/bin/zsh 。 如果您希望脚本可以移植到具有Zsh但位于不同位置的其他系统,那么您可能希望在脚本顶部使用此hashbang行 :

 #!/usr/bin/env zsh 

如果用户可以通过键入zsh并按Enter键来运行Zsh,那么将它放在脚本的顶部通常会起作用(并运行用户将运行的相同zsh可执行文件)。 这不适用于100%的系统 – 从技术上讲, env本身不必在/usr/bin中提供 – 但实际上,如果zsh在用户的$PATH ,它很难失败。

有关Zsh中算术评估的更多信息,包括浮点运算,请参见Z Shell手册中的11算术评估

降低输出精度

Zsh中的浮点变量x可能会比你想象的那样显示比你想要的更精确: $x

 % ((x=.5)) % echo "$x" 0.5000000000 

在没有这些额外零的情况下扩展它的一种方法是使用算术扩展:

 % echo "$((x))" 0.5 

您还可以使用printf命令显示精度有限的值:

 % printf '%.2f\n' "$x" 0.50 

即使shell不支持浮点运算,它也适用于其他shell。 (有些shell没有内置的printf ,但你仍然可以使用该命令,因为在/usr/bin/printf安装了一个独立的可执行版本 。)除了舍入之外, printf命令不会执行其他算法。

即使在您不需要数字格式的情况下, printf通常是比shell脚本中的echo更好的选择 。

如果您感兴趣,Zsh手册(如上所述)解释了实际存储浮点值的精确程度。 (通常是IEEE 754 binary64 。)

您可以使用更简单的语法(在Bash中也是如此)。

您的脚本可以正常使用,但您可以简化其语法以提高可读性:

  • 您的脚本不需要{}提供的分组 。
  • A ; 在一行的末尾是多余的。
  • 里面(( ))$i可以写i
  • 你可以使用(( ))而不是let 。 如果没有领先的$ ,它会在不扩展到结果的情况下进行评估。 并非所有shell都支持这种非扩展forms,但Bash和Zsh(以及其他一些)支持这种forms。
  • 当您不希望发生分词时,即使这样做是可选的(如本例所示) ,也可以引用 。 但是,您可以在同一双引号文本中包含多个扩展。

在开始时省略了关于n的信息(你可能非常需要这个用于你的目的,但我不知道它的用途是什么),我建议:

 #!/bin/zsh for ((i = .5; i < 10; i++)) do ((c = i + 1)) echo "$i + $c" done 

或者,如果您不希望打印这些额外的零:

 #!/bin/zsh for ((i = .5; i < 10; i++)) do echo "$((i)) + $((i + 1))" done 

这打印:

 0.5 + 1.5 1.5 + 2.5 2.5 + 3.5 3.5 + 4.5 4.5 + 5.5 5.5 + 6.5 6.5 + 7.5 7.5 + 8.5 8.5 + 9.5 9.5 + 10.5 

最后,要解决一个可能的混淆点:

  • 可以使用i = .5分配i ,因为它被计算为算术表达式,因为它出现在(( )) ,因此允许使用=周围的空格。 这些空间不是必需的,您不需要使用它们,但您可以这样做。 (我已经这样做了。)
  • 算术表达式之外,分配shell变量要求=两侧都没有空格。 也就是说,通常你必须写var=val ,而不是var = val 。 类似地, 算术表达式之外, 访问shell变量的值需要$ (例如, $i${i} )。

我会指出,虽然bash仅限于整数数学,但ksh93不是。 所以这个(更简单的例子)工作正常:

 $ for ((i=0.5; i<3; i=$((i+1)))); do print $i ; done 0.5 1.5 2.5 

我们使用i=$((i+1))而不是i++因为++只适用于整数。

所以我认为这是原始提问者想要的(除了当然没有用bash完成):

 $ for ((i=0.5; i<10; i=$((i+1)))); do c=$((i+1)) ; print $i + $c ; done 0.5 + 1.5 1.5 + 2.5 2.5 + 3.5 3.5 + 4.5 4.5 + 5.5 5.5 + 6.5 6.5 + 7.5 7.5 + 8.5 8.5 + 9.5 9.5 + 10.5 

这一切都在shell本身内完成,无需外部命令。 如果需要使用bash ,那么使用外部命令的建议是可行的方法。

Bash本身不支持浮点数,但是有一个名为bc的程序可以进行十进制算术运算。

您应该重写脚本以使用BC(又名最佳计算器)或其他其他实用程序 。 那么,你怎么能这样做? 由于bash内置本身不支持浮点,因此无法使用for循环。 您可以使用另一个变量来控制循环内部并使用1 (或0 )作为起始点。

有一种方法来伪造分数,有点尴尬但在某些情况下它是可用的:

 #!/bin/bash { n=9 echo "$n" for (( i=5; $i <100; i+=10 )) do let "c=$i+10" echo "$(( $i / 10 )).$(( $i % 10 )) + $(( $c / 10 )).$(( $c % 10 ))" done } 

使用div / modulo,您实际上也可以做一些漂亮的(读取:笨拙)计算。

 #!/bin/bash { n=9; echo "$n"; for i in `seq .5 10`; do c=`bc <<< $i+1`; echo $i "+" $c; done; }