Bash Shell下的BMI计算器

5

我正在尝试使用Linux中的Bash shell创建一个脚本来计算BMI。我知道这只是一些傻乎乎的事情,但似乎无法使它正常工作。它不会做除法运算。你能看出我错在哪里吗?

     #!/bin/bash
     #==============================================================
     # Script Name: bmicalc
     # By:          mhj
     # Date:        March 25, 2014
     # Purpose:     calculates your bmi from your weight & height
     #===============================================================
     #Get your weight and height
     echo -n "What is your weight in pounds? "
     read weight
     echo -n "What is your height in inches? "
     read height
     #calculate your bmi
     let total_weight=$weight*703
     let total_height=$height*$height
     bmi=$total_weight/$total_height
     echo "Your weight is $weight"
 echo "Your height is $height"
 echo -n "Your BMI is $bmi"

1
请注意,let 是过时的语法;现代形式是 total_weight=$(( weight * 703 ))total_height=$(( height * height )) 等。 - Charles Duffy
话虽如此,Bash本地数学运算只支持整数;如果你想要一个准确的数字,你需要使用浮点数运算,而Bash并不支持。其中一个常见的解决方案是使用awk来实现。 - Charles Duffy
请参考 http://mywiki.wooledge.org/BashFAQ/022 了解如何在 Bash 中进行浮点数计算的详细介绍。 - Charles Duffy
不错的项目!:D 我一直很钦佩Bash程序员... - inf3rno
5个回答

2
如果您需要一个非整数的答案,可以使用bc
$ weight=160
$ height=70
$ echo "Your BMI is $(bc <<< "scale=3; ($weight * 703) / ($height * $height)")"
Your BMI is 22.955
$ 

scale=3; 告诉 bc 输出到小数点后三位。根据需要更改此值。


2
你已经接近成功了,你只需要再添加一个“let”关键字:
let bmi=$total_weight/$total_height

替代方案

在shell中,有许多方法可以实现算术运算。首选的标准方法是使用$(( ))语法:

total_weight=$(( $weight * 703 ))

这个和下面的expr基本上是POSIX sh中唯一可用的。还有一个$[ ],但它已经被弃用了,并且大部分情况下与双括号相同。

如果将变量声明为整数,可以获得一些语法效率。具有整数属性的参数会导致所有赋值表达式的RHS具有算术上下文:

declare -i weight height bmi total_weight total_height
total_weight=weight*703
total_height=height*height
bmi=total_weight/total_height

不再使用 let

您也可以直接使用 (( )) 语法。

(( total_weight=weight*703 ))
(( total_height=height*height ))
(( bmi=total_weight/total_height ))

最后,expr只是shell中的一个痛点。
total_weight=$(expr $weight '*' 703) # Have to escape the operator symbol or it will glob expand
total_height=$(expr $height '*' $height) # Also there's this crazy subshell

… 平庸,但是完整!

最后,在bash数组中,索引将始终具有算术上下文。(但这并不适用于此处。)

然而,这些方法都不能进行浮点数计算,因此您的除法将始终被截断。如果需要小数值,请使用bcawk或另一种编程语言。


话虽如此,“declare -i”是Bash特有的语法,使用“(( ))”也是如此,然而“$(( ))”符合POSIX标准。 - Charles Duffy
啊,现在我明白了。 (我第一次阅读时错过了吗?还是你在编辑后修改了?) - Charles Duffy
那里:我认为这是所有算术表达式上下文语法的调查。 - kojiro
@DigitalTrauma 不是,我提到了它。请看我的最近编辑。 - kojiro
我使用了declare -i weight height bmi total_weight total_height的命令,total_weight=weight703,total_height=heightheight,bmi=total_weight/total_height,这个方法很有效。我只是想要BMI的大致概念,而不是精确数字,所以Bash对我来说很适用!谢谢 - Maggi3339336
我从未听说过declare -i。谢谢。原来bash也有“类型”;-) - Digital Trauma

1

为什么要费心去处理变量呢?如果您不介意使用本地(仅限整数)数学运算,这与您从 let 获取的是相同的东西:

echo "Your BMI is $(( (weight * 703) / (height * height) ))"

...或者使用awk进行更精确的计算:

awk -v weight="$weight" -v height="$height" \
  'BEGIN { printf "%f\n", ((weight * 703) / (height * height)) }'

0

正如指针一样...Bash不支持浮点数运算,只支持整数。所以你计算BMI的数字会有偏差。如果你要使用除法进行计算,应该使用bc

例如:

7/3 = 2(而不是2.33333333)

7%3 = 1


0
我会用 bc 来完成这个任务。变量 scale 决定了答案的小数位数:
bmi=$(bc <<< "scale=2; $total_weight/$total_height")

或者,您可以使用-l加载标准数学库,将scale设置为20:

bmi=$(bc -l <<< "$total_weight/$total_height")

awk总是一个选项:

bmi=$(awk -v w="$total_weight" -v h="$total_height" 'BEGIN { print w/h }')

如果使用-l选项调用bc,则会预加载一个数学库,并将默认比例设置为20。 - Digital Trauma
@DigitalTrauma 谢谢,我查了手册,但只是说“定义标准数学库”。现在正在编辑。 - Tom Fenech

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