
Сегодня утром я искал информацию о том, как сравнить два десятичных числа в 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()
например).