Сравнение десятичных чисел в bash

Сравнение десятичных чисел в bash

Сегодня утром я искал информацию о том, как сравнить два десятичных числа в bash, и пришел к такому ответу:Как сравнить с числом с плавающей точкой в ​​скрипте оболочки. Однако этот не включает в себяэтот ответ здесь:

$ [[ ((3.56 < 2.90)) ]]; echo $?
1
$ [[ ((3.56 < 4.90)) ]]; echo $?
0

Учитывая, что этот ответ был отклонен и выглядит как необычный башизм, можно ли доверять этой арифметической оценке с точки зрения точности?

решение1

bashне понимает чисел с плавающей точкой.
Цитата из bashстраницы руководства, разделаАРИФМЕТИЧЕСКАЯ ОЦЕНКА:

Оценка выполняется в целых числах фиксированной ширины […].

Так ((3 < 4))или ((3 < 2))на самом деле являются правильными арифметическими выражениями. Вы можете ввести следующее:

$ echo "$((3 < 4)) -- $((3 < 2))"

выход:1 -- 0

Но $ echo $((3.3 < 3.6))вернет сообщение об ошибке синтаксиса. В вашем примере вы фактически сравниваете строки. Отсюда пример:

$ [[ ((3.56 < 04.90)) ]]; echo $?

выход:1

решение2

Внутри [[...]] <— для сравнения строк.

Таким образом, [[ 3.56 < 2.90 ]]or [[ (3.56 < 2.90) ]]or [[ ((3.56 < 2.90)) ]]or [[ (((3.56 < 2.90))) ]]... просто сравнивает 3.56строку со 2.90строкой лексически (и лексически, 3больше, чем, 10например).

Для сравнения целых чисел это [[ 3 -lt 2 ]]или (( 3 < 2 )). Если вам нужно сравнение с плавающей точкой, вам нужно ksh93, zshили yashили внешняя утилита вроде awkили perl; bashне может этого сделать.

Например, вы можете определить функцию следующим образом:

compare() (IFS=" "
  exec awk "BEGIN{if (!($*)) exit(1)}"
)

Что вы можете использовать, например, так:

if compare '1.5*10 < 1e3'; then
  echo less
fi

Или даже если это имеет значение:

if compare '"bar" < "foo"'...

для сравнения строк.

Не передавайте этой compareфункции неконтролируемые внешние данные, поскольку это может привести к уязвимости внедрения команд (данные интерпретируются как awkкод, awkс его помощью можно запускать команды, system()например).

Связанный контент