Как сравнить числа в Bash?
Я не могу заставить работать числовые сравнения в моем скрипте. Вот код, который я использую:
echo "введите два числа"
read a b
echo "a=$a"
echo "b=$b"
if [ $a > $b ]; then
echo "a больше чем b"
else
echo "b больше чем a"
fi
Проблема в том, что происходит сравнение с начала числа, то есть 9 больше, чем 10, но 1 больше 09.
Как я могу преобразовать числа в тип, чтобы провести корректное сравнение?
5 ответ(ов)
Есть еще одна приятная вещь, о которой некоторые люди, возможно, не знают:
echo $(( a < b ? a : b ))
Этот код выведет наименьшее число между a
и b
.
В Bash я предпочитаю использовать конструкцию [[ n -gt m ]]
, так как она больше подходит для условных операций, в отличие от (( ))
, который больше ориентирован на арифметические вычисления.
[[ n -gt m ]]
Если же мне нужно выполнять более сложные операции, я использую:
(( (n + 1) > m ))
Каждый в конце концов выбирает свой подход. Печально, что некоторые люди навязывают свои неофициальные стандарты.
Можно также сделать следующим образом:
[[ 'n + 1' -gt m ]]
Это позволяет добавить нечто большее, чем просто арифметические операции, что удобно при использовании [[ ]]
.
Однострочное решение для проверки, больше ли значение переменной a
значения переменной b
, на Bash:
a=2; b=1; [[ ${a} -gt ${b} ]] && echo "true" || echo "false"
Пояснения:
[[ ... ]]
используется для условий (см. документацию).-gt
— оператор сравнения "больше" (подробнее здесь).&&
и||
выполняют логические операции: если предыдущее условие истинно, выполняется первая команда после&&
, в противном случае — команда после||
(см. информацию).- Использование
${}
позволяет расширять переменные, как описано тут.
Скобочные конструкции (например, [[ $a -gt $b ]]
или (( $a > $b ))
) недостаточны, если вы хотите сравнивать числа с плавающей точкой; это приведет к синтаксической ошибке. Если вам нужно сравнивать числовые значения с плавающей точкой или число с плавающей точкой с целым числом, вы можете использовать (( $(bc <<< "...") ))
.
Например:
a=2.00
b=1
if (( $(bc <<<"$a > $b") )); then
echo "a больше чем b"
else
echo "a не больше чем b"
fi
Вы можете включить более одного сравнения в условие if
. Например:
a=2.
b=1
c=1.0000
if (( $(bc <<<"$b == $c && $b < $a") )); then
echo "b равно c, но меньше чем a"
else
echo "b либо не равно c, либо не меньше a"
fi
Это будет полезно, если вы хотите проверить, находится ли числовая переменная (будь то целое число или число с плавающей точкой) в числовом диапазоне.
Этот код также может сравнивать числа с плавающей запятой. Он использует AWK (это не чистый Bash). Однако это не должно быть проблемой, так как AWK — это стандартная команда POSIX, которая, скорее всего, поставляется по умолчанию с вашей операционной системой.
$ awk 'BEGIN {return_code=(-1.2345 == -1.2345) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
0
$ awk 'BEGIN {return_code=(-1.2345 >= -1.2345) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
0
$ awk 'BEGIN {return_code=(-1.2345 < -1.2345) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
1
$ awk 'BEGIN {return_code=(-1.2345 < 2) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
0
$ awk 'BEGIN {return_code=(-1.2345 > 2) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
Чтобы сделать код короче для использования, вы можете воспользоваться следующей функцией:
compare_nums()
{
# Функция для сравнения двух чисел (чисел с плавающей запятой или целых) с использованием AWK.
# Функция не будет ничего печатать, но вернет 0 (если сравнение истинно) или 1
# (если сравнение ложно) в качестве кодов выхода, так что ее можно использовать напрямую в однострочных командах shell.
#############
### Использование ###
### Обратите внимание, что оператор сравнения необходимо заключить в кавычки.
#############
# compare_nums 1 ">" 2 # возвращает ложь
# compare_nums 1.23 "<=" 2 # возвращает истину
# compare_nums -1.238 "<=" -2 # возвращает ложь
#############################################
num1=$1
op=$2
num2=$3
E_BADARGS=65
# Убедитесь, что предоставленные числа действительно являются числами.
if ! [[ $num1 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num1 не является числом"; return $E_BADARGS; fi
if ! [[ $num2 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num2 не является числом"; return $E_BADARGS; fi
# Если вы хотите также вывести код выхода (вместо того, чтобы только возвращать его), раскомментируйте
# строку awk ниже и закомментируйте раскомментированную строку, которая на две строки ниже.
#awk 'BEGIN {print return_code=('$num1' '$op' '$num2') ? 0 : 1; exit} END {exit return_code}'
awk 'BEGIN {return_code=('$num1' '$op' '$num2') ? 0 : 1; exit} END {exit return_code}'
return_code=$?
return $return_code
}
$ compare_nums -1.2345 ">=" -1.2345 && echo true || echo false
true
$ compare_nums -1.2345 ">=" 23 && echo true || echo false
false
Таким образом, функция compare_nums
позволяет просто и удобно сравнивать числа, используя мощные инструменты, доступные в AWK, в комбинации с Bash.
Как выводить команды оболочки по мере их выполнения
Назначение значений по умолчанию для переменных оболочки одной командой в bash
Как указать приватный SSH-ключ для выполнения команды shell в Git?
Как сделать паузу в shell-скрипте на одну секунду перед продолжением?
Как использовать 'grep' для непрерывного потока?