私が試した増分として0.02のbashでforループを作成したい
for ((i=4.00;i<5.42;i+=0.02))
do
commands
done
しかし、それはうまくいきませんでした。
bash
man page を読み取ると、次の情報が得られます。
for (( expr1 ; expr2 ; expr3 )) ; do list ; done
まず、算術式
expr1
は、以下の算術評価で説明されているルールに従って評価されます。 [...]
そして、このセクションを取得します
算術評価
シェルを使用すると、特定の状況下で算術式を評価できます(
let
およびdeclare
組み込みコマンドと算術展開を参照)。評価はオーバーフローのチェックなしで固定幅整数で行われます[...]
したがって、整数値以外ではfor
ループを使用できないことがはっきりとわかります。
1つの解決策は、単純にすべてのループコンポーネントに100を掛けて、後で使用できるようにすることです。
for ((k=400;k<542;k+=2))
do
i=$(bc <<<"scale=2; $k / 100" ) # when k=402 you get i=4.02, etc.
...
done
シェルでのループを避けます。
算術演算を行う場合は、awk
またはbc
を使用します。
awk '
BEGIN{
for (i = 4.00; i < 5.42; i+ = 0.02)
print i
}'
または
bc << EOF
for (i = 4.00; i < 5.42; i += 0.02) i
EOF
awk
(bc
とは対照的に)はプロセッサーで動作することに注意してくださいdouble
浮動小数点数表現(おそらく IEEE 754 タイプ)。結果として、これらの数値はこれらの10進数の2進近似であるため、いくつかの驚きがあるかもしれません。
$ gawk 'BEGIN{for (i=0; i<=0.3; i+=0.1) print i}'
0
0.1
0.2
OFMT="%.17g"
を追加すると、0.3
がない理由がわかります。
$ gawk 'BEGIN{OFMT="%.17g"; for (i=0; i<=0.5; i+=0.1) print i}'
0
0.10000000000000001
0.20000000000000001
0.30000000000000004
0.40000000000000002
0.5
bc
は任意の精度を行うため、この種の問題はありません。
デフォルトでは(OFMT
で出力形式を変更するか、明示的な形式指定でprintf
を使用しない限り)、awk
は浮動小数点数の表示に%.6g
を使用します。したがって、1,000,000を超える浮動小数点数の場合は1e6以上に切り替わり、大きな数の場合は小数部を切り捨てます(100000.02は100000として表示されます)。
シェルループを実際に使用する必要がある場合、たとえばそのループの反復ごとに特定のコマンドを実行したい場合は、zsh
、yash
のような浮動小数点演算サポートを備えたシェルを使用します。またはksh93
または上記の1つのコマンド(またはseq
が利用可能な場合)で値のリストを生成し、その出力をループします。
お気に入り:
unset -v IFS # configure split+glob for default Word splitting
for i in $(seq 4 0.02 5.42); do
something with "$i"
done
または:
seq 4 0.02 5.42 | while IFS= read i; do
something with "$i"
done
プロセッサの浮動小数点数の制限をプッシュしない限り、seq
は、浮動小数点近似によって発生するエラーを、上記のawk
バージョンよりも適切に処理します。
seq
(a GNUコマンド)がない場合は、次のような関数として、より信頼性の高いものを作成できます。
seq() { # args: first increment last
bc << EOF
for (i = $1; i <= $3; i += $2) i
EOF
}
それはseq 100000000001 0.000000001 100000000001.000000005
のようなものに適しています。ただし、サポートされていないコマンドに渡す場合は、任意の高精度の数値を使用してもあまり効果がないことに注意してください。
「seq」を使用-一連の数値を出力します
seq FIRST INCREMENT LAST
for i in $(seq 4.00 0.02 5.42)
do
echo $i
done
他の人が示唆したように、あなたはbcを使うことができます:
i="4.00"
while [[ "$(bc <<< "$i < 5.42")" == "1" ]]; do
# do something with i
i="$(bc <<< "$i + 0.02")"
done