Сравнение чисел в Bash
Я начинаю изучать написание сценариев для терминала bash, но не могу понять, как заставить сравнения работать должным образом. Сценарий, который я использую:
echo "enter two numbers";
read a b;
echo "a=$a";
echo "b=$b";
if [ $a \> $b ];
then
echo "a is greater than b";
else
echo "b is greater than a";
fi;
Проблема в том, что он сравнивает число с первой цифры, т.е. 9 больше 10, а 1 больше 09.
Как я могу преобразовать числа в тип, чтобы сделать истинное сравнение?
Ответы
Ответ 1
В bash вы должны сделать свой чек в арифметическом контексте:
if (( a > b )); then
...
fi
Для оболочек POSIX, которые не поддерживают (())
, вы можете использовать -lt
и -gt
.
if [ "$a" -gt "$b" ]; then
...
fi
Вы можете получить полный список операторов сравнения с help test
.
Ответ 2
Легко и просто
#!/bin/bash
a=2462620
b=2462620
if [ "$a" -eq "$b" ];then
echo "They're equal";
fi
Вы можете проверить эту таблицу, если хотите больше сравнения чисел в удивительном мире Bash Scripting.
Вкратце, целые числа можно сравнить только с:
-eq # equal
-ne # not equal
-lt # less than
-le # less than or equal
-gt # greater than
-ge # greater than or equal
Ответ 3
Есть также одна хорошая вещь, о которой некоторые люди могут не знать:
echo $(( a < b ? a : b ))
Этот код напечатает наименьшее число из a
и b
Ответ 4
В Bash я предпочитаю делать это, поскольку он больше относится к нему как к условной операции, в отличие от использования (( ))
, который является более арифметическим.
[[ N -gt M ]]
Если я не делаю сложные вещи, например
(( (N + 1) > M ))
Но у всех есть свои предпочтения. Печально то, что некоторые люди навязывают свои неофициальные стандарты.
Update:
Вы также можете это сделать:
[[ 'N + 1' -gt M ]]
Что позволяет добавить что-то еще, что вы могли бы сделать с помощью [[ ]]
помимо арифметических материалов.
Ответ 5
Этот код также может сравнивать поплавки. Он использует 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()
{
# Function to compare two numbers (float or integers) by using awk.
# The function will not print anything, but it will return 0 (if the comparison is true) or 1
# (if the comparison is false) exit codes, so it can be used directly in shell one liners.
#############
### Usage ###
### Note that you have to enclose the comparison operator in quotes.
#############
# compare_nums 1 ">" 2 # returns false
# compare_nums 1.23 "<=" 2 # returns true
# compare_nums -1.238 "<=" -2 # returns false
#############################################
num1=$1
op=$2
num2=$3
E_BADARGS=65
# Make sure that the provided numbers are actually numbers.
if ! [[ $num1 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num1 is not a number"; return $E_BADARGS; fi
if ! [[ $num2 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num2 is not a number"; return $E_BADARGS; fi
# If you want to print the exit code as well (instead of only returning it), uncomment
# the awk line below and comment the uncommented one which is two lines below.
#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
Ответ 6
Я решил это, используя небольшую функцию для преобразования строк версии в простые целочисленные значения, которые можно сравнить:
function versionToInt() {
local IFS=.
parts=($1)
let val=1000000*parts[0]+1000*parts[1]+parts[2]
echo $val
}
Это делает два важных предположения:
Например
versionToInt 12.34.56 # --> 12034056
versionToInt 1.2.3 # --> 1002003
Пример тестирования, соответствует ли команда npm
минимальному требованию...
NPM_ACTUAL=$(versionToInt $(npm --version)) # Capture npm version
NPM_REQUIRED=$(versionToInt 4.3.0) # Desired version
if [ $NPM_ACTUAL \< $NPM_REQUIRED ]; then
echo "Please update to [email protected]"
exit 1
fi
Ответ 7
Если у вас есть плавающие числа, вы можете написать функцию, а затем использовать ее, например:
#!/bin/bash
function float_gt() {
perl -e "{if($1>$2){print 1} else {print 0}}"
}
x=3.14
y=5.20
if [ $(float_gt $x $y) == 1 ] ; then
echo "do stuff with x"
else
echo "do stuff with y"
fi
Ответ 8
В скобках (например, [[ $a -gt $b ]]
или (( $a > $b ))
) недостаточно, если вы хотите использовать также числа с плавающей точкой; это сообщило бы об ошибке синтаксиса. Если вы хотите сравнить числа с плавающей точкой или число с плавающей точкой с целым числом, вы можете использовать (( $(bc <<< "...") ))
.
Например,
a=2.00
b=1
if (( $(bc <<<"$a > $b") )); then
echo "a is greater than b"
else
echo "a is not greater than b"
fi
Вы можете включить более одного сравнения в оператор if. Например,
a=2.
b=1
c=1.0000
if (( $(bc <<<"$b == $c && $b < $a") )); then
echo "b is equal to c but less than a"
else
echo "b is either not equal to c and/or not less than a"
fi
Это полезно, если вы хотите проверить, находится ли числовая переменная (целочисленная или нет) в числовом диапазоне.