Сравните десятичные дроби в Bash во время цикла
В приведенном ниже коде ShellCheck выдает ошибку в while
пункт.
count=10.0
while [ $count -le 20.0 ]
do
echo "Hello"
count=$(bc<<< "scale=4; (count+0.1)")
done
ShellCheck говорит:
Десятичные числа не поддерживаются, используйте целые числа или bc
Я не совсем уверен, как использовать BC в while
петля.
while [ $(bc <<< "scale=4; (count -le 20.0)" ]
Как сравнить десятичные числа в предложении while? Любой совет?
3 ответа
Bash не поддерживает арифметику с плавающей запятой. Вы можете использовать bc:
count="10.0"
limit="12.0"
increment="0.1"
while [ "$(bc <<< "$count < $limit")" == "1" ]; do
echo "Hello"
count=$(bc <<< "$count+$increment")
done
или awk:
while awk 'BEGIN { if ('$count'>='$limit') {exit 1}}'; do
echo "Hello"
count=$(bc <<< "$count+$increment")
done
Мне просто интересно: почему бы (напрямую) не сосчитать с 10.0 до 12.0?
for i in $(seq 10.0 0.1 12.0); do
echo "Hello"
done
Bash не поддерживает арифметику с плавающей точкой. Ты можешь использовать bc
для этого сравнения тоже:
count=10.0
while : ;
do
out=$(bc -l<<< "$count<20.0")
[[ $out == 0 ]] && { echo "Reached limit" ; exit 0; }
echo "Hello"
count=$(bc<<< "scale=4; ($count+0.1)")
done
Обратите внимание, что я добавил недостающие $
в count
внутри цикла, где вы обновляете count
,
Хотя bash не обрабатывает числа с плавающей запятой, seq
Утилита делает. [Примечание 1]
Основной синтаксис seq FIRST INCREMENT LAST
так что в вашем случае вы могли бы использовать
for count in "$(seq 10.0 0.1 20.0)"; do
# something with $count
done
Если вы предоставляете два аргумента, предполагается, что они ПЕРВЫЙ и ПОСЛЕДНИЙ, с INCREMENT равным 1. Если вы предоставляете только один аргумент, он считается ЛАСТНЫМ, причем ПЕРВЫЙ и INCREMENT равны 1. Как в вашем примере, последовательность включительно, поэтому будут получены как FIRST, так и LAST при условии, что INCREMENT равномерно делит FIRST-LAST.
Вы также можете включить явный формат:
$ seq -f "%06.3f" 1 .5 2
01.000
01.500
02.000
Недостатком этого метода является то, что он предварительно вычисляет весь набор значений. Если цикл будет выполняться сотни тысяч раз, это может занять много памяти, и в этом случае вы могли бы использовать замену канала или процесса:
while read count; do
# something with count
done < <(seq 10.0 0.000001 20.0)
Заметки
seq
не Posix, но он почти всегда присутствует; он входит в состав GNU coreutils, и аналогичная утилита, доступная в Mac OS X) работает в NetBSD начиная с 3.0, а FreeBSD - с 9.0.