Я пытаюсь сравнить два числа с плавающей запятой в bash script. Я имею переменные, например.
let num1=3.17648e-22
let num2=1.5
Теперь я просто хочу сделать простое сравнение этих двух чисел:
st=`echo "$num1 < $num2" | bc`
if [ $st -eq 1]; then
echo -e "$num1 < $num2"
else
echo -e "$num1 >= $num2"
fi
К сожалению, у меня есть некоторые проблемы с правильной обработкой num1, который может иметь "электронный формат".: (
Любая помощь, подсказки приветствуются!
Ответ 1
Удобнее
Это может быть сделано более удобно, используя числовой контекст Bash:
if (( $(echo "$num1 > $num2" |bc -l) )); then
…
fi
объяснение
Передача через базовую команду калькулятора bc
возвращает 1 или 0.
Опция -l
эквивалентна --mathlib
; загружает стандартную математическую библиотеку.
Заключив все выражение в двойные скобки (( ))
сможете преобразовать эти значения в значения true или false.
Пожалуйста, убедитесь, что установлен базовый калькулятор bc
.
Это в равной степени работает для чисел с плавающей запятой в научном формате, при условии, что используется заглавная буква E
, например, num1=3.44E6
Ответ 2
bash обрабатывает только целые математические выражения
но вы можете использовать команду bc
следующим образом:
$ num1=3.17648E-22
$ num2=1.5
$ echo $num1'>'$num2 | bc -l
0
$ echo $num2'>'$num1 | bc -l
1
Обратите внимание, что знак экспоненты должен быть прописным.
Ответ 3
Лучше использовать awk
для не целочисленной математики. Вы можете использовать эту служебную функцию bash:
numCompare() {
awk -v n1="$1" -v n2="$2" 'BEGIN {printf "%s " (n1<n2?"<":">=") " %s\n", n1, n2}'
}
И назовите его как:
numCompare 5.65 3.14e-22
5.65 >= 3.14e-22
numCompare 5.65e-23 3.14e-22
5.65e-23 < 3.14e-22
numCompare 3.145678 3.145679
3.145678 < 3.145679
Ответ 4
Чистое решение bash для сравнения поплавков без экспоненциальной нотации, ведущих или конечных нулей:
if [ ${FOO%.*} -eq ${BAR%.*} ] && [ ${FOO#*.} \> ${BAR#*.} ] || [ ${FOO%.*} -gt ${BAR%.*} ]; then
echo "${FOO} > ${BAR}";
else
echo "${FOO} <= ${BAR}";
fi
Порядок логических операторов имеет значение. Целочисленные части сравниваются, поскольку числа и дробные части преднамеренно сравниваются как строки. Переменные разбиваются на целые и дробные части, используя этот метод.
Не будет сравнивать поплавки с целыми числами (без точки).
Ответ 5
вы можете использовать awk в сочетании с условием bash if, awk будет печатать 1 или 0, и они будут интерпретироваться с помощью предложения if с true или false.
if (( $(awk 'BEGIN {print ("'$d1'" >= "'$d2'")}') )); then
echo "yes"
else
echo "no"
fi
Ответ 6
будьте осторожны при сравнении чисел, которые являются версиями пакета, например, если grep 2.20 больше версии 2.6:
$ awk 'BEGIN { print (2.20 >= 2.6) ? "YES" : "NO" }'
NO
$ awk 'BEGIN { print (2.2 >= 2.6) ? "YES" : "NO" }'
NO
$ awk 'BEGIN { print (2.60 == 2.6) ? "YES" : "NO" }'
YES
Я решил такую проблему с такой функцией shell/awk:
# get version of GNU tool
toolversion() {
local prog="$1" operator="$2" value="$3" version
version=$($prog --version | awk '{print $NF; exit}')
awk -vv1="$version" -vv2="$value" 'BEGIN {
split(v1, a, /\./); split(v2, b, /\./);
if (a[1] == b[1]) {
exit (a[2] '$operator' b[2]) ? 0 : 1
}
else {
exit (a[1] '$operator' b[1]) ? 0 : 1
}
}'
}
if toolversion grep '>=' 2.6; then
# do something awesome
fi
Ответ 7
Я использовал ответы отсюда и поместил их в функцию, вы можете использовать ее так:
is_first_floating_number_bigger 1.5 1.2
result="${__FUNCTION_RETURN}"
После вызова echo $result
в этом случае будет 1
, в противном случае 0
.
Функция:
is_first_floating_number_bigger () {
number1="$1"
number2="$2"
[ ${number1%.*} -eq ${number2%.*} ] && [ ${number1#*.} \> ${number2#*.} ] || [ ${number1%.*} -gt ${number2%.*} ];
result=$?
if [ "$result" -eq 0 ]; then result=1; else result=0; fi
__FUNCTION_RETURN="${result}"
}
Или версия с отладочным результатом:
is_first_floating_number_bigger () {
number1="$1"
number2="$2"
echo "... is_first_floating_number_bigger: comparing ${number1} with ${number2} (to check if the first one is bigger)"
[ ${number1%.*} -eq ${number2%.*} ] && [ ${number1#*.} \> ${number2#*.} ] || [ ${number1%.*} -gt ${number2%.*} ];
result=$?
if [ "$result" -eq 0 ]; then result=1; else result=0; fi
echo "... is_first_floating_number_bigger: result is: ${result}"
if [ "$result" -eq 0 ]; then
echo "... is_first_floating_number_bigger: ${number1} is not bigger than ${number2}"
else
echo "... is_first_floating_number_bigger: ${number1} is bigger than ${number2}"
fi
__FUNCTION_RETURN="${result}"
}
Просто сохраните функцию в отдельном файле .sh
и включите ее следующим образом:
. /path/to/the/new-file.sh
Ответ 8
Конечно, если вам не нужна действительно арифметика с плавающей точкой, а только арифметика, например, в значениях доллара, где всегда есть ровно две десятичных цифры, вы можете просто отбросить точку (эффективно умножая на 100) и сравнить полученные целые числа.
if [[ $((10#${num1/.})) < $((10#${num2/.})) ]]; then
...
Это, очевидно, требует, чтобы вы были уверены, что оба значения имеют одинаковое количество десятичных знаков.
Ответ 9
Этот скрипт может помочь, когда я проверяю, превышает ли установленная версия grails
чем минимальная. Надеюсь, поможет.
#!/bin/bash
min=1.4
current='echo $(grails --version | head -n 2 | awk '{print $NF}' | cut -c 1-3)'
if [ 1 -eq 'echo "${current} < ${min}" | bc' ]
then
echo "yo, you have older version of grails."
else
echo "Hurray, you have the latest version"
fi
Ответ 10
Используйте оболочку korn, в bash вам, возможно, придется сравнивать десятичную часть отдельно
#!/bin/ksh
X=0.2
Y=0.2
echo $X
echo $Y
if [[ $X -lt $Y ]]
then
echo "X is less than Y"
elif [[ $X -gt $Y ]]
then
echo "X is greater than Y"
elif [[ $X -eq $Y ]]
then
echo "X is equal to Y"
fi
Ответ 11
Используя bashj (https://sourceforge.net/projects/bashj/), мутант bash с поддержкой java, вы просто пишете (и его легко читать):
#!/usr/bin/bashj
#!java
static int doubleCompare(double a,double b) {return((a>b) ? 1 : (a<b) ? -1 : 0);}
#!bashj
num1=3.17648e-22
num2=1.5
comp=j.doubleCompare($num1,$num2)
if [ $comp == 0 ] ; then echo "Equal" ; fi
if [ $comp == 1 ] ; then echo "$num1 > $num2" ; fi
if [ $comp == -1 ] ; then echo "$num2 > $num1" ; fi
Конечно, bashj bash/java hybridation предлагает гораздо больше...
Ответ 12
пожалуйста, проверьте ниже отредактированный код: -
#!/bin/bash
export num1=(3.17648*e-22)
export num2=1.5
st=$(('echo "$num1 < $num2"| bc'))
if [ $st -eq 1 ]
then
echo -e "$num1 < $num2"
else
echo -e "$num1 >= $num2"
fi
это хорошо работает
Ответ 13
Как насчет этого? = D
VAL_TO_CHECK="1.00001"
if [ $(awk '{printf($1 >= $2) ? 1 : 0}' <<<" $VAL_TO_CHECK 1 ") -eq 1 ] ; then
echo "$VAL_TO_CHECK >= 1"
else
echo "$VAL_TO_CHECK < 1"
fi
Ответ 14
awk
и подобные ему инструменты (я смотрю на вас, sed
...) должны быть отправлены на свалку старых проектов, с кодом, который все слишком боятся трогать, поскольку он написан на языке, никогда не читающем.
Или вы - относительно редкий проект, которому нужно расставить приоритеты оптимизации использования процессора над оптимизацией обслуживания кода... в таком случае продолжайте.
Если нет, то почему бы просто не использовать что-то читаемое и явное, например, python
? Ваши коллеги по программированию и будущие я будут вам благодарны. Вы можете использовать python
встроенный в Bash, как и все остальные.
num1=3.17648E-22
num2=1.5
if python -c "exit(0 if $num1 < $num2 else 1)"; then
echo "yes, $num1 < $num2"
else
echo "no, $num1 >= $num2"
fi
Ответ 15
num1=0.555
num2=2.555
if [ 'echo "$num1>$num2"|bc' -eq 1 ]; then
echo "$num1 is greater then $num2"
else
echo "$num2 is greater then $num1"
fi
Ответ 16
Решение, поддерживающее научную нотацию с показателями в верхнем и нижнем регистре (например, 12.00e4
):
if (( $(bc -l <<< "${value1/e/E} < ${value2/e/E}") ))
then
echo "$value1 is less than $value2"
fi
Ответ 17
Я опубликовал это как ответ на fooobar.com/info/17738725/... когда он был закрыт как дубликат этого вопроса, так что здесь это так, как это применимо и здесь:
Для простоты и ясности просто используйте awk для вычислений, так как он является стандартным инструментом UNIX и поэтому с такой же вероятностью будет присутствовать как bc, и с ним намного проще работать синтаксически.
По этому вопросу:
$ cat tst.sh
#!/bin/bash
num1=3.17648e-22
num2=1.5
awk -v num1="$num1" -v num2="$num2" '
BEGIN {
print "num1", (num1 < num2 ? "<" : ">="), "num2"
}
'
$ ./tst.sh
num1 < num2
и для этого другого вопроса, который был закрыт как дубликат этого:
$ cat tst.sh
#!/bin/bash
read -p "Operator: " operator
read -p "First number: " ch1
read -p "Second number: " ch2
awk -v ch1="$ch1" -v ch2="$ch2" -v op="$operator" '
BEGIN {
if ( ( op == "/" ) && ( ch2 == 0 ) ) {
print "Nope..."
}
else {
print ch1 '"$operator"' ch2
}
}
'
$ ./tst.sh
Operator: /
First number: 4.5
Second number: 2
2.25
$ ./tst.sh
Operator: /
First number: 4.5
Second number: 0
Nope...