Уникайте петель в оболонках.
Якщо ви хочете займатися арифметикою, використовуйте 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 ). Як результат, оскільки ці числа є двійковими наближеннями цих десяткових чисел, у вас можуть виникнути деякі сюрпризи:
$ 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для відображення чисел з плаваючою комою, тому перемикається на 1e6 і вище для чисел з плаваючою комою вище 1 000 000 і обрізає дробову частину для високих чисел (100000.02 відображатиметься як 100000).
Якщо вам дійсно потрібно використовувати цикл оболонки, тому що, наприклад, ви хочете виконати конкретні команди для кожної ітерації цього циклу, або використовуйте оболонку з арифметичною підтримкою з плаваючою комою zsh, yashабо, ksh93або генеруйте список значень однією командою, як вище (або 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(команда GNU), ви можете зробити більш надійний як функцію, наприклад:
seq() { # args: first increment last
bc << EOF
for (i = $1; i <= $3; i += $2) i
EOF
}
Це було б краще для таких речей seq 100000000001 0.000000001 100000000001.000000005. Однак зауважте, що наявність чисел з довільно високою точністю не допоможе багато, якщо ми збираємось передавати їх командам, які їх не підтримують.