whileループを誤って使用していますか?

whileループを誤って使用していますか?

私はしなければならないプロジェクトのリストを見つけました。私は次のようなコードを作成しました。

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

これが私がしなければならないことを行うのに悪い方法かもしれないことを知っていますが、それでも止まっています。ループを間違って使っているようですが、whileよくわかりません。whileループの目的は、他の種類のコインを追加できることを確認して、値がゼロより大きいことを確認することです。

ベストアンサー1

コードの最も明白な問題は、すべてのwhileループがループ内で絶対に変更されない変数(たとえば$quarter)をチェックするため、ループ条件が決して偽にならず、ループが無限に繰り返されることです。

次のループの1つを見てみましょう。

while [ $quarter -ge 0 ]
do
qNum=$(( qNum+1 ))
amount=$(( $amount-25 ))
done

> 0 の場合、$quarter制御フローはループに入り、増減$qNum$amountますが、$quarter同じままであるため、別のループ反復を実行します。


コードの修正はリファクタリングによって最適です。

  • amountグローバル変数が関数の副作用に設定されることに依存するのではなく、引数を受け入れ、その結果をstdout(可能であれば)出力するように関数を再構築してください。

    • 結果stdout:関数は、使用可能かどうかにかかわらず、後でスクリプトで処理getamt()できます(変更されていません)。何を呼び出しても、この出力はを使用して変数としてキャプチャできます。残念ながら、関数が複数の値を返す必要がある場合は機能しません。この場合、関数は戻り値を改行文字で区切って印刷することができ、値に表示されない文字を表示できます。このような出力形式を選択することもできますecho $amountamountgetamtamount=$(getamt)

      quarter=3  
      dime=1  
      nickel=4  
      

      そして、その出力を評価し、関数の戻り値を使用してローカル変数を設定します。$(yourfunction); echo $quarter

    • パラメータ:関数は、グローバル変数から読み取るのではなく、パラメータchange()(つまり呼び出す)で計算する必要がある変更を取ることができます。最初の引数、2番目の引数などのamount 2.50インデックスを使用して、関数(またはコンテキストに従ってスクリプト)に指定された引数にアクセスできます。$1$2

  • bc小数点以下の桁数を削除すると、複数の呼び出しを避けることができます一度次に、bash算術評価を使用します。現在の交換アイテム${quarter%???}も削除されます。どの最後の3文字は、ユーザーが小数点の2桁より大きいまたは小さい値を入力することを決定した場合、望ましくない結果を生成します。同様の方法で${quarter%%.*}最初の項目以降のすべての項目を削除します.

  • コメントを使用する(aで始まり#行末まで続く):
    たとえば、amount=${amount%%.*} # remove decimal places
    ほとんどのコードは今は明確に見えるかもしれませんが、他の人にははっきりしないかもしれません。数ヶ月後にもう一度見直す必要があり、もう必要ありません。

  • 正直なところ、あなたのスクリプトが現在返すコインの数をどのように計算するのかは完全にわかりません。変化量を計算する最も一般的な方法は、利用可能な最高のコイン値から始まり、その値の変化量と「一致する」可能な限り多くのコインを配布するためのグリディアルゴリズムです。1、変更金額からこれらのコインの合計値を差し引いた後、変更金額がゼロに達するまで次の(より小さい)コイン値に進みます(つまり、全体の変更金額を構成するのに十分なコインが配布されました)。
    1確認できるコイン数を計算するにはモジュロ算術または、変更量がコイン値よりも小さくなるまでループを実行して、変更量から現在のコイン値を減算します(つまり、現在の値の他のコインを除算すると、余りにも多くの残高が返されます)。

おすすめ記事