我使用while循环错误吗?

智障的*_*障的人 2 shell-script

我找到了一份要做的项目清单,其中一个是会产生大量变化的项目。我做了这个代码:

getamt() {
echo "Enter amount of money."
read amount
echo "OK."
}
change() {
amount=$(echo "$amount*100" | bc)
quarter=$(echo "($amount-25)" | bc)
dime=$(echo "($amount-10)" | bc)
nickel=$(echo "($amount-5)" | bc)
penny=$(echo "($amount-1)" | bc )
quarter=${quarter%???}
dime=${dime%???}
nickel=${nickel%???}
penny=${penny%???}
amount=${amount%???}
qNum=0
dNum=0
nNum=0
pNum=0
}

getchange() {
while [ $quarter -ge 0 ]
do
qNum=$(( qNum+1 ))
amount=$(( $amount-25 ))
done
while [ $dime -ge 0 ]
do
dNum=$(( dNum+1 ))
amount=$(( $amount-10 ))
done
while [ $nickel -ge 0 ]
do
nNum=$(( nNum+1 ))
amount=$(( $amount-5 ))
done
while [ $penny -ge 0 ]
do
pNum=$(( nNum+1 ))
amount=$(( $amount-1 ))
done
}

display() {
echo "Your change is:"
echo "$qNum quarters"
echo "$dNum dimes"
echo "$nNum nickels"
echo "$pNum pennies"
}

getamt
change
getchange
display
Run Code Online (Sandbox Code Playgroud)

我知道这可能是做我需要做的事情的一种糟糕方式,但它被卡住了。我想我可能while错误地使用了循环,但我不知道。我使用while循环的目的是检查是否可以在那里添加另一种类型的硬币,以便检查该值是否大于零。

n.s*_*.st 7

您的代码最明显的问题是您的所有while循环都会检查一个$quarter在循环内永远不会改变的变量(例如),因此循环条件永远不会变为假并且循环无休止地重复。

让我们看看其中一个循环:

while [ $quarter -ge 0 ]
do
qNum=$(( qNum+1 ))
amount=$(( $amount-25 ))
done
Run Code Online (Sandbox Code Playgroud)

如果$quarter> 0,则控制流进入循环,$qNum递增并$amount递减,但$quarter保持不变,因此您将进入另一个循环迭代。


通过重构代码来修复代码效果最好:

  • 与其依赖于amount设置为函数副作用的全局变量,不如重写您的函数以接受参数并将其结果输出到stdout(在可能的情况下)。

    • 结果stdout:您的函数getamt()可以echo $amount而不是依赖于amount可用(和未更改)以便稍后在脚本中进行处理。任何调用getamt都可以将此输出捕获到带有amount=$(getamt).
      不幸的是,当一个函数需要返回多个值时,这不起作用——在这种情况下,您可以让函数打印由换行符或您知道不会出现在值中的字符分隔的返回值。你甚至可以选择像这样的输出格式

      quarter=3  
      dime=1  
      nickel=4  
      
      Run Code Online (Sandbox Code Playgroud)

      并评估该输出以使用函数的返回值设置局部变量: $(yourfunction); echo $quarter

    • 参数:您的函数change()可以将它应该计算的变化量作为参数(即您将调用amount 2.50)而不是从全局变量中读取它。你可以通过它们的索引访问给你的函数(或你的脚本,取决于上下文)$1的参数:第一个参数,$2第二个参数,等等。

  • 您可以bc通过只切除一次小数位并在此之后仅使用 bash 算术评估来避免几次调用。您当前的替换${quarter%???}还会删除任何最后三个字符,如果您的用户决定输入多于(或少于)两位小数的值,这将产生不需要的结果。使用类似的东西${quarter%%.*}删除(包括)第一个之后的所有内容.

  • 使用注释(以 a 开头#并一直持续到行尾):
    例如amount=${amount%%.*} # remove decimal places
    ,您的大部分代码现在对您来说似乎很明显,但对其他人来说可能并不明显,而且也不会很明显当你在几个月后不得不再次查看它时,你就不再需要了。

  • 老实说,我不完全确定您的脚本应该如何计算此刻要返回的硬币数量。计算找零的最常见方法是贪心算法,该算法从最高可用硬币价值开始,分配与“适合”找零金额1 的该价值硬币数量,然后从找零金额中减去这些硬币的总价值,然后继续下一个(较小的)硬币价值,依此类推,直到找零金额达到 0(即已分配足够的硬币来弥补总找零金额)。
    1要计算此硬币数量,您可以查看模运算 或者只是从循环中的找零金额中减去当前硬币价值,直到找零金额小于硬币价值(即,如果您分配另一个当前价值的硬币,您将返回太多找零)。