Подтвердить что ты не робот

Сравнение с плавающей точкой с переменной в 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 - это то, что выдает терминал.

4b9b3361

Ответ 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