Сравнение с плавающей точкой с переменной в bash
Я хочу сравнить переменную с плавающей точкой с целым числом.
Я знаю, что это не лучшее, что можно сделать с bash, но весь мой script уже написан в bash.
$ number может быть любым целым числом. Если он ниже или равен 50, я хочу output1, для всех остальных я хочу выход с другой переменной k. Это то, что у меня есть до сих пор:
number=43
test=$(echo "scale=2; $number/50" | bc -l)
echo "$test"
for k in {1..5}
do
if ["$test" -le 1]
then echo "output"
elif ["$test" -gt $k]
then echo "output$k"
fi
done
Если я попробую с тестом = 0.43, первый цикл даже не работает. Я думаю, что это связано с целым числом и с плавающей точкой, но не может заставить его работать.
Что-нибудь мне не хватает?
PS: этот [0.43: command not found
- это то, что выдает терминал.
Ответы
Ответ 1
Bash не может обрабатывать поплавки. Труба вместо bc
:
if [ $(echo " $test > $k" | bc) -eq 1 ]
Ошибка, которую вы видите, состоит в том, что для команды test
(т.е. [
) нужны пробелы до и после
Лучше использовать (( ... ))
, так как вы сравниваете такие числа:
if (( $(bc <<< "$test > $k") ))
Часть в цикле должна выглядеть так:
if (( $(bc <<< "$test <= 1") ))
then
echo "output"
elif (( $(bc <<< "$test > $k") ))
then
echo "output$k"
fi
Реляционные выражения оцениваются в 0, если отношение ложно, и 1, если отношение истинно [source]. Обратите внимание, что это поведение GNU bc
, и оно не является POSIX
compiant.
Ответ 2
Вид старого вопроса, но он имеет дополнительный ответ, который я думаю.
В то время как работа с трубопроводом на высокоточный калькулятор (bc или dc) работает, это связано с вилкой и дополнительным процессом, поскольку эти калькуляторы не встроены в bash. Однако одна вещь, встроенная в систему, - printf
. Поэтому, если вы можете иметь дело с числами, находящимися в определенном количестве десятичных знаков, вы можете "подделать" сравнения с плавающей запятой, используя такую функцию:
#!/usr/bin/env bash
function [[[ () {
local LANG=C lhs rhs
printf -v lhs '%07.3f' "$1"; lhs=${lhs/./}
printf -v rhs '%07.3f' "$3"; rhs=${rhs/./}
case "$2" in
-lt) return $(( ! ( 10#$lhs < 10#$rhs ) )) ;;
-le) return $(( ! ( 10#$lhs <= 10#$rhs ) )) ;;
-eq) return $(( ! ( 10#$lhs == 10#$rhs ) )) ;;
-ge) return $(( ! ( 10#$lhs >= 10#$rhs ) )) ;;
-gt) return $(( ! ( 10#$lhs > 10#$rhs ) )) ;;
esac
}
number=${1:-43}
test=$(dc -e "2k $number 50 / p")
echo "$test"
for k in {1..5}; do
if [[[ "$test" -le 1 ]]]; then
echo "output"
elif [[[ "$test" -gt "$k" ]]]; then
echo "output $k"
fi
done
Несколько вещей, чтобы рассмотреть здесь.
- Я назвал функцию
[[[
симпатичной. Вы можете назвать его как хотите. ntest
или mynumericcomparison
или даже [[[
.
-
printf
- это внутренняя функция внутри bash, поэтому, несмотря на то, что она на вашем пути, она не стоит вилкой.
- В соответствии с этим функция поддерживает номера до 999.999. Если вам нужны более высокие цифры (или более высокая точность), отрегулируйте форматы
printf
.
-
10#
в начале каждой переменной внутри оператора case
заключается в принуждении к тому, чтобы сравнение происходило в базе 10, поскольку нулевое число в противном случае могло бы быть интерпретировано как восьмеричное.
Смотрите также: http://mywiki.wooledge.org/BashFAQ/022