为什么bash算术中的除法将大多数百分比计算为0?


15

尝试对脚本进行bash运算,但$e直到最后才更新。输出说明一切。

max=5
for e in $(seq 1 1 $max); do 
    percent=$(( $e/$max*100 ))
    echo "echo $e / $max : = $percent"
done

Tl; DR:显示1..5(以百分比表示)。

输出:

echo 1 / 5 : = 0
echo 2 / 5 : = 0
echo 3 / 5 : = 0
echo 4 / 5 : = 0
echo 5 / 5 : = 100

为什么是这样?


1
相关信息:Bash在执行计算时仅考虑整数而不考虑输入(尽管与此处描述的问题不同,无法通过对操作重新排序来很好地解决它。)
Eliah Kagan

Answers:


24

bash无法处理非整数算术运算。只要所有表达式都是整数,它就会为您提供正确的结果。因此,您需要避免在计算中的某个地方获取非整数值。

在您的情况下,当您评估等等时1 / 52 / 5它将在bash中创建对应于一些非整数值的整数零值,并且结果相应地为零。优先除法和乘法的相同,并且相同的先例运算总是执行左到右,因为它们被放置在表达。

解决方法之一是先进行乘法,然后进行除法,以便bash不必处理非整数值。更正的表达式将是

$ max=5; for e in $(seq 1 1 $max); do percent=$(( $e*100/$max )); echo "echo $e / $max : = $percent"; done
echo 1 / 5 : = 20
echo 2 / 5 : = 40
echo 3 / 5 : = 60
echo 4 / 5 : = 80
echo 5 / 5 : = 100

1
子表达式1/5不会创建非整数值。它创建整数值0,因为1除以5 的整数的结果是0。进一步的操作成功使用了该值0。这不是OP的目的,但是没有操作会创建非整数值,并且任何操作都不会失败。
伊莱亚·卡根

@EliahKagan感谢您指出缺陷。编辑。
souravc

16

Bash在这种算术上做得不是很好。这是您的问题:

$ echo $((1/5))
0
$ echo $((2/5))
0
$ echo $((4/5))
0
$ echo $((4/5))
0

如果您需要处理非整数值,则可以使用 bc

$ max=5; for e in $(seq 1 1 "$max"); do percent=$(bc <<< "scale=1 ; $e/$max*100") ; echo "echo $e / $max : = ${percent%.*}"; done
echo 1 / 5 : = 20
echo 2 / 5 : = 40
echo 3 / 5 : = 60
echo 4 / 5 : = 80
echo 5 / 5 : = 100

(感谢@Arronical指出如何将输出格式化为整数)


我一定会看一下,再次感谢!
Cybex

1
您可以.0通过将$percent 回声更改为${percent%.*}:) 来修剪输出:)
Arronical '16

11

与bash不同,awk提供完整的浮点运算。例如:

$ awk -v max=5 'BEGIN{for (e=1;e<=max;e++) print "echo " e " / " max " : = " 100*e/max}' 
echo 1 / 5 : = 20
echo 2 / 5 : = 40
echo 3 / 5 : = 60
echo 4 / 5 : = 80
echo 5 / 5 : = 100

5

尝试

percent=$(( $e*100/$max ))

:)

请参阅以下内容的算术评估:

man bash

它仅支持整数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.