it-swarm.com.ru

Как проверить, является ли переменная числом в Bash?

Я просто не могу понять, как мне убедиться, что аргумент, переданный моему сценарию, является числом или нет.

Все, что я хочу сделать, это что-то вроде этого:

test *isnumber* $1 && VAR=$1 || echo "need a number"

Любая помощь?

482
Flávio Amieiro

Одним из подходов является использование регулярного выражения, например, так:

re='^[0-9]+$'
if ! [[ $yournumber =~ $re ]] ; then
   echo "error: Not a number" >&2; exit 1
fi

Если значение не обязательно является целым числом, попробуйте соответствующим образом изменить регулярное выражение; например:

^[0-9]+([.][0-9]+)?$

... или для обработки чисел со знаком:

^[+-]?[0-9]+([.][0-9]+)?$
648
Charles Duffy

Без башмизмов (работает даже в Системе В Ш),

case $string in
    ''|*[!0-9]*) echo bad ;;
    *) echo good ;;
esac

Это отклоняет пустые строки и строки, содержащие не-цифры, принимая все остальное.

Отрицательные числа или числа с плавающей точкой требуют дополнительной работы. Идея состоит в том, чтобы исключить -/. в первом «плохом» шаблоне и добавить больше «плохих» шаблонов, содержащих их нецелевое использование (?*-*/*.*.*)

232
jilles

Следующее решение может также использоваться в базовых оболочках, таких как Bourne, без необходимости использования регулярных выражений. По существу, любые операции оценки числовых значений с использованием нечисловых значений приводят к ошибке, которая будет неявно рассматриваться как ложная в Shell:

"$var" -eq "$var"

как в:

#!/bin/bash

var=a

if [ -n "$var" ] && [ "$var" -eq "$var" ] 2>/dev/null; then
  echo number
else
  echo not a number
fi

Вы также можете проверить на $? код возврата операции, которая является более явной:

[ -n "$var" ] && ["$var" -eq "$var"] 2>/dev/null
if [ $? -ne 0 ]; then
   echo $var is not number
fi

Перенаправление стандартной ошибки предназначено для того, чтобы скрыть сообщение «ожидается целочисленное выражение», которое распечатывает bash, если у нас нет числа.

CAVEATS(благодаря комментариям ниже):

  • Числа с десятичными точками не определены как действительные "числа"
  • Использование [[ ]] вместо [ ] всегда будет иметь значение true
  • Большинство не-Bash-оболочек всегда будут оценивать это выражение как true
  • Поведение в Bash недокументировано и поэтому может меняться без предупреждения
  • Если значение включает пробелы после числа (например, «1 a»), возникает ошибка, например bash: [[: 1 a: syntax error in expression (error token is "a")
  • Если значение совпадает с var-name (например, i = "i"), выдает ошибку, например bash: [[: i: expression recursion level exceeded (error token is "i")
154
Alberto Zaccagni

Это проверяет, является ли число неотрицательным целым числом, является ли оно независимым от Shell (то есть без искажений) и использует только встроенные функции Shell:

[ -z "${num##[0-9]*}" ] && echo "is a number" || echo "is not a number";

НО IS НЕПРАВИЛЬНО.
Как jilles прокомментировал и предложил в свой ответ это правильный способ сделать это, используя Shell-шаблоны.

[ ! -z "${num##*[!0-9]*}" ] && echo "is a number" || echo "is not a number";
33
mrucci

Никто не предложил bash's расширенное сопоставление с образцом :

[[ $1 == ?(-)+([0-9]) ]] && echo "$1 is an integer"
28
glenn jackman

Я удивлен тем, что решения для непосредственного разбора числовых форматов в Shell . Shell не очень подходит для этого, так как является DSL для управления файлами и процессами .. Есть несколько анализаторов чисел, чуть ниже, например:

isdecimal() {
  # filter octal/hex/ord()
  num=$(printf '%s' "$1" | sed "s/^0*\([1-9]\)/\1/; s/'/^/")

  test "$num" && printf '%f' "$num" >/dev/null 2>&1
}

Измените «% f» на тот формат, который вам требуется.

27
pixelbeat

Я смотрел на ответы и .... понял, что никто не думал о числах FLOAT (с точкой)!

Использование grep тоже замечательно.
- E означает расширенное регулярное выражение
- q означает тихий (не повторяет)
- QE является комбинацией обоих.

Чтобы проверить прямо в командной строке:

$ echo "32" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is: 32

$ echo "3a2" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is empty (false)

$ echo ".5" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer .5

$ echo "3.2" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is 3.2

Использование в скрипте bash:

check=`echo "$1" | grep -E ^\-?[0-9]*\.?[0-9]+$`

if [ "$check" != '' ]; then    
  # it IS numeric
  echo "Yeap!"
else
  # it is NOT numeric.
  echo "nooop"
fi

Чтобы соответствовать JUST целым числам, используйте это:

# change check line to:
check=`echo "$1" | grep -E ^\-?[0-9]+$`
15
Sergio Abreu

Просто продолжение до @mary. Но из-за того, что у меня недостаточно представителей, я не смог опубликовать это как комментарий к этому сообщению. В любом случае, вот что я использовал:

isnum() { awk -v a="$1" 'BEGIN {print (a == a + 0)}'; }

Функция вернет «1», если аргумент является числом, в противном случае вернет «0». Это работает как для целых чисел, так и для чисел с плавающей точкой. Использование это что-то вроде:

n=-2.05e+07
res=`isnum "$n"`
if [ "$res" == "1" ]; then
     echo "$n is a number"
else
     echo "$n is not a number"
fi
12
triple_r

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html

Вы также можете использовать классы персонажей bash.

if [[ $VAR = *[[:digit:]]* ]]; then
 echo "$VAR is numeric"
else
 echo "$VAR is not numeric"
fi

Числа будут включать пробел, десятичную точку и «e» или «E» для числа с плавающей запятой.

Но если вы укажете шестнадцатеричное число в стиле C, то есть «0xffff» или «0XFFFF», [[: digit:]] вернет true. Здесь есть небольшая ловушка, bash позволяет вам делать что-то вроде «0xAZ00» и при этом считать его цифрой (разве это не странная причуда компиляторов GCC, позволяющих использовать нотацию 0x для баз, отличных от 16 ??? )

Возможно, вы захотите проверить «0x» или «0X» перед проверкой, является ли оно числовым, если ваш ввод абсолютно ненадежен, если вы не хотите принимать шестнадцатеричные числа. Это будет достигнуто путем:

if [[ ${VARIABLE:1:2} = "0x" ]] || [[ ${VARIABLE:1:2} = "0X" ]]; then echo "$VAR is not numeric"; fi
7
ultrasawblade

Старый вопрос, но я просто хотел придерживаться своего решения. Этот не требует никаких странных трюков с Shell или полагается на то, чего не было всегда.

if [ -n "$(printf '%s\n' "$var" | sed 's/[0-9]//g')" ]; then
    echo 'is not numeric'
else
    echo 'is numeric'
fi

По сути, он просто удаляет все цифры из входных данных, и если у вас останется строка не нулевой длины, тогда это не число.

7
Sammitch
test -z "${i//[0-9]}" && echo digits || echo no no no

${i//[0-9]} заменяет любую цифру в значении $i пустой строкой, см. man -P 'less +/parameter\/' bash. -z проверяет, имеет ли результирующая строка нулевую длину.

если вы также хотите исключить случай, когда $i пуст, вы можете использовать одну из следующих конструкций:

test -n "$i" && test -z "${i//[0-9]}" && echo digits || echo not a number
[[ -n "$i" && -z "${i//[0-9]}" ]] && echo digits || echo not a number
6
user2683246
[[ $1 =~ ^-?[0-9]+$ ]] && echo "number"

Не забудьте - включить отрицательные числа!

6
D_I

Пока не могу комментировать, поэтому я добавлю свой собственный ответ, который является расширением ответа Гленна Джекмана с использованием сопоставления с шаблоном bash.

Моей первоначальной потребностью было идентифицировать числа и различать целые числа и числа с плавающей запятой. Определения функций вычитаются в:

function isInteger() {
    [[ ${1} == ?(-)+([0-9]) ]]
}

function isFloat() {
    [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]
}

Я использовал модульное тестирование (с shUnit2), чтобы проверить, что мои шаблоны работают так, как задумано:

oneTimeSetUp() {
    int_values="0 123 -0 -123"
    float_values="0.0 0. .0 -0.0 -0. -.0 \
        123.456 123. .456 -123.456 -123. -.456
        123.456E08 123.E08 .456E08 -123.456E08 -123.E08 -.456E08 \
        123.456E+08 123.E+08 .456E+08 -123.456E+08 -123.E+08 -.456E+08 \
        123.456E-08 123.E-08 .456E-08 -123.456E-08 -123.E-08 -.456E-08"
}

testIsIntegerIsFloat() {
    local value
    for value in ${int_values}
    do
        assertTrue "${value} should be tested as integer" "isInteger ${value}"
        assertFalse "${value} should not be tested as float" "isFloat ${value}"
    done

    for value in ${float_values}
    do
        assertTrue "${value} should be tested as float" "isFloat ${value}"
        assertFalse "${value} should not be tested as integer" "isInteger ${value}"
    done

}

Примечания: Шаблон isFloat можно изменить, чтобы он был более терпимым в отношении десятичной точки (@(.,)) и символа E (@(Ee)). Мои модульные тесты тестируют только значения, которые являются целочисленными или плавающими, но не содержат недопустимых входных данных.

5
karttu

Я бы попробовал это:

printf "%g" "$var" &> /dev/null
if [[ $? == 0 ]] ; then
    echo "$var is a number."
else
    echo "$var is not a number."
fi

Примечание: это распознает nan и inf как число.

5
overflowed

Самый простой способ - проверить, содержит ли он нецифровые символы. Вы заменяете все цифры на ничто и проверяете длину. Если есть длина, это не число.

if [[ ! -n ${input//[0-9]/} ]]; then
    echo "Input Is A Number"
fi
4
Andy

@Charles Dufy и другие уже дали четкий ответ. Чистым решением для bash было бы использовать следующее:

string="-12,345"
if [[ "$string" =~ ^-?[0-9]+[.,]?[0-9]*$ ]]
then
    echo $string is a number
else
    echo $string is not a number
fi

Хотя для действительных чисел не обязательно иметь число перед точкой radix .

Чтобы обеспечить более полную поддержку плавающих чисел и научных обозначений (многие программы на C/Fortran или иначе будут экспортировать float таким способом), полезным дополнением к этой строке будет следующее:

string="1.2345E-67"
if [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]?-?[0-9]+$ ]]
then
    echo $string is a number
else
    echo $string is not a number
fi

Таким образом, можно найти способ различать типы чисел, если вы ищете какой-либо конкретный тип:

string="-12,345"
if [[ "$string" =~ ^-?[0-9]+$ ]]
then
    echo $string is an integer
Elif [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*$ ]]
then
    echo $string is a float
Elif [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]-?[0-9]+$ ]]
then
    echo $string is a scientific number
else
    echo $string is not a number
fi

Примечание: мы могли бы перечислить синтаксические требования для десятичной и научной нотации, одна из которых заключается в том, чтобы использовать запятую как точку отсчета, а также ".". Мы бы тогда утверждали, что должна быть только одна такая точка радиуса. В плавающем [Ee] может быть два знака +/-. Я узнал еще несколько правил из работы Аулу и проверил на наличие плохих строк, таких как '' '-' '-E-1' '0-0'. Вот мои инструменты regex/substring/expr, которые, кажется, удерживают:

parse_num() {
 local r=`expr "$1" : '.*\([.,]\)' 2>/dev/null | tr -d '\n'` 
 nat='^[+-]?[0-9]+[.,]?$' \
 dot="${1%[.,]*}${r}${1##*[.,]}" \
 float='^[\+\-]?([.,0-9]+[Ee]?[-+]?|)[0-9]+$'
 [[ "$1" == $dot ]] && [[ "$1" =~ $float ]] || [[ "$1" =~ $nat ]]
} # usage: parse_num -123.456
4
Aulo

Я использую expr . Он возвращает ненулевое значение, если вы пытаетесь добавить ноль к нечисловому значению:

if expr -- "$number" + 0 > /dev/null 2>&1
then
    echo "$number is a number"
else
    echo "$number isn't a number"
fi

Возможно, можно использовать bc , если вам нужны нецелые числа, но я не верю, что bc ведет себя точно так же. Добавление нуля к нечисленному номеру возвращает вас к нулю и также возвращает значение нуля. Может быть, вы можете объединить bc и expr. Используйте bc, чтобы добавить ноль к $number. Если ответ 0, попробуйте expr, чтобы убедиться, что $number не равен нулю.

4
David W.

Поскольку мне пришлось вмешиваться в это в последнее время и, как karttu's , больше всего подходить к юнит-тесту. Я пересмотрел код и добавил некоторые другие решения, попробуйте сами, чтобы увидеть результаты:

#!/bin/bash

    # N={0,1,2,3,...} by syntaxerror
function isNaturalNumber()
{
 [[ ${1} =~ ^[0-9]+$ ]]
}
    # Z={...,-2,-1,0,1,2,...} by karttu
function isInteger() 
{
 [[ ${1} == ?(-)+([0-9]) ]]
}
    # Q={...,-½,-¼,0.0,¼,½,...} by karttu
function isFloat() 
{
 [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]
}
    # R={...,-1,-½,-¼,0.E+n,¼,½,1,...}
function isNumber()
{
 isNaturalNumber $1 || isInteger $1 || isFloat $1
}

bools=("TRUE" "FALSE")
int_values="0 123 -0 -123"
float_values="0.0 0. .0 -0.0 -0. -.0 \
    123.456 123. .456 -123.456 -123. -.456 \
    123.456E08 123.E08 .456E08 -123.456E08 -123.E08 -.456E08 \
    123.456E+08 123.E+08 .456E+08 -123.456E+08 -123.E+08 -.456E+08 \
    123.456E-08 123.E-08 .456E-08 -123.456E-08 -123.E-08 -.456E-08"
false_values="blah meh mooh blah5 67mooh a123bc"

for value in ${int_values} ${float_values} ${false_values}
do
    printf "  %5s=%-30s" $(isNaturalNumber $value) ${bools[$?]} $(printf "isNaturalNumber(%s)" $value)
    printf "%5s=%-24s" $(isInteger $value) ${bools[$?]} $(printf "isInteger(%s)" $value)
    printf "%5s=%-24s" $(isFloat $value) ${bools[$?]} $(printf "isFloat(%s)" $value)
    printf "%5s=%-24s\n" $(isNumber $value) ${bools[$?]} $(printf "isNumber(%s)" $value)
done

Поэтому isNumber () включает в себя тире, запятые и экспоненциальные обозначения и, следовательно, возвращает TRUE для целых чисел и чисел с плавающей запятой, где, с другой стороны, isFloat () возвращает FALSE для целочисленных значений и isInteger () аналогично возвращает ЛОЖЬ на поплавках. Для вашего удобства все как один лайнер:

isNaturalNumber() { [[ ${1} =~ ^[0-9]+$ ]]; }
isInteger() { [[ ${1} == ?(-)+([0-9]) ]]; }
isFloat() { [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]; }
isNumber() { isNaturalNumber $1 || isInteger $1 || isFloat $1; }
3
3ronco

Это может быть достигнуто с помощью grep, чтобы увидеть, соответствует ли рассматриваемая переменная расширенному регулярному выражению.

Тест целого числа 1120:

yournumber=1120
if [ $(echo "$yournumber" | grep -qE '^[0-9]+$'; echo $?) -ne "0" ]; then
    echo "Error: not a number."
else
    echo "Valid number."
fi

Вывод: Valid number.

Тест нецелого 1120a:

yournumber=1120a
if [ $(echo "$yournumber" | grep -qE '^[0-9]+$'; echo $?) -ne "0" ]; then
    echo "Error: not a number."
else
    echo "Valid number."
fi

Вывод: Error: not a number.


Объяснение

  • Переключатель grep, -E позволяет нам использовать расширенное регулярное выражение '^[0-9]+$'. Это регулярное выражение означает, что переменная должна содержать только [] числа от 0-9 с нуля до девяти от ^, начинающиеся до конца $ переменной, и должна содержать как минимум + один символ.
  • Переключатель grep, тихий -q отключает любой вывод независимо от того, находит ли он что-либо.
  • $? - это статус выхода предыдущей выполненной команды. Состояние выхода 0 означает успех, а что-либо большее означает ошибку. Команда grep имеет статус выхода 0, если она находит совпадение, и 1, если нет;
  • $() - это подоболочка, которая позволяет нам выполнить другую команду и затем использовать вывод.

Таким образом, объединив все это в подоболочку $(), мы echo переменная $yournumber и | направляют ее в grep, которая с переключателем -q молча соответствует расширенному регулярному выражению -E выражению '^[0-9]+$'. Затем мы echo из состояния выхода $?, которое будет 0, если grep успешно нашел совпадение, и 1, если это не так.

Теперь вне вложенной оболочки $() и обратно в условное выражение if мы берем выходные данные, либо 0, либо 1 из вложенной оболочки $(), и проверяем, не является ли -ne не равным "0". Если он не соответствует, статус выхода будет 1, который не соответствует "0". Затем мы будем echo "Error: not a number.". В случае совпадения выходной статус будет иметь 0, который равен "0", а в противном случае мы echo "Valid number.".


Для поплавков или пар

Мы можем просто изменить регулярное выражение с '^[0-9]+$' на '^[0-9]*+\.?[0-8]+$' для float или double.

Test float 1120.01:

yournumber=1120.01
if [ $(echo "$yournumber" | grep -qE '^[0-9]*+\.?[0-8]+$'; echo $?) -ne "0" ]; then
    echo "Error: not a number."
else
    echo "Valid number."
fi

Вывод: Valid number.

Test float 11.20.01:

yournumber=11.20.01
if [ $(echo "$yournumber" | grep -qE '^[0-9]*+\.?[0-8]+$'; echo $?) -ne "0" ]; then
    echo "Error: not a number."
else
    echo "Valid number."
fi

Вывод: Error: not a number.


Для негативов

Чтобы разрешить отрицательные целые числа, просто измените регулярное выражение с '^[0-9]+$' на '^\-?[0-9]+$'.

Чтобы разрешить отрицательные числа с плавающей запятой или двойные числа, просто измените регулярное выражение с '^[0-9]*+\.?[0-8]+$' на '^\-?[0-9]*+\.?[0-8]+$'.

2
Joseph Shih

Сделали то же самое здесь с регулярным выражением, которое проверяет всю часть и десятичную часть, разделенные точкой. 

re="^[0-9]*[.]{0,1}[0-9]*$"

if [[ $1 =~ $re ]] 
then
   echo "is numeric"
else
  echo "Naahh, not numeric"
fi
1
Jerome

Я попробовал рецепт ультразвука, так как он показался мне наиболее практичным, и не смог заставить его работать. В конце концов я разработал другой способ, основанный, как и другие, на подстановке параметров, на этот раз с заменой регулярного выражения:

[[ "${var//*([[:digit:]])}" ]]; && echo "$var is not numeric" || echo "$var is numeric"

Он удаляет каждый символ: digit: class в $ var и проверяет, остались ли у нас пустые строки, что означает, что оригинал был только числами.

Что мне нравится в этом, так это его небольшой размер и гибкость. В этой форме он работает только для целых 10 без разделителей, хотя, безусловно, вы можете использовать сопоставление с образцом, чтобы удовлетворить его другим потребностям.

1
ata

Вы можете использовать «let» тоже так:

[ ~]$ var=1
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s a number
[ ~]$ var=01
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s a number
[ ~]$ var=toto
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s not a number
[ ~]$ 

Но я предпочитаю использовать оператор "= ~" Bash 3+, как некоторые ответы в этой теме.

1
Idriss Neumann
  • переменная для проверки

    number=12345 или number=-23234 или number=23.167 или number=-345.234

  • проверить числовой или не числовой

    echo $number | grep -E '^-?[0-9]*\.?[0-9]*$' > /dev/null

  • принять решение о дальнейших действиях на основе статуса выхода из вышеупомянутого

    if [ $? -eq 0 ]; then echo "Numeric"; else echo "Non-Numeric"; fi

1
Atanu

Вслед за ответом Дэвида В. с октября 2013 г., если использовать expr, это может быть лучше

test_var=`expr $am_i_numeric \* 0` >/dev/null 2>&1
if [ "$test_var" = "" ]
then
    ......

Если числовое значение, умноженное на 1, даст вам то же значение (включая отрицательные числа). В противном случае вы получите null, который вы можете проверить 

1
Jon T

Я использую printf в качестве других упомянутых ответов, если вы предоставите строку формата "% f" или "% i", printf выполнит проверку за вас. Синтаксис проще, чем изобретать чеки, он прост и короток, а printf вездесущ. Так что, на мой взгляд, это достойный выбор - вы также можете использовать следующую идею для проверки ряда вещей, она полезна не только для проверки чисел. 

declare  -r CHECK_FLOAT="%f"  
declare  -r CHECK_INTEGER="%i"  

 ## <arg 1> Number - Number to check  
 ## <arg 2> String - Number type to check  
 ## <arg 3> String - Error message  
function check_number() { 
  local NUMBER="${1}" 
  local NUMBER_TYPE="${2}" 
  local ERROR_MESG="${3}"
  local -i PASS=1 
  local -i FAIL=0   
  case "${NUMBER_TYPE}" in 
    "${CHECK_FLOAT}") 
        if ((! $(printf "${CHECK_FLOAT}" "${NUMBER}" &>/dev/random;echo $?))); then 
           echo "${PASS}"
        else 
           echo "${ERROR_MESG}" 1>&2
           echo "${FAIL}"
        fi 
        ;;                 
    "${CHECK_INTEGER}") 
        if ((! $(printf "${CHECK_INTEGER}" "${NUMBER}" &>/dev/random;echo $?))); then 
           echo "${PASS}"
        else 
           echo "${ERROR_MESG}" 1>&2
           echo "${FAIL}"
        fi 
        ;;                 
                     *) 
        echo "Invalid number type format: ${NUMBER_TYPE} to check_number()." 1>&2
        echo "${FAIL}"
        ;;                 
   esac
} 

>$ var=45

>$ (($(check_number $var "${CHECK_INTEGER}" "Error: Found $var - An integer is required."))) && { echo "$var+5" | bc; } 

1
user4401178

Чтобы поймать отрицательные числа:

if [[ $1 == ?(-)+([0-9.]) ]]
    then
    echo number
else
    echo not a number
fi
1
user28490

Я нашел довольно короткую версию:

function isnum()
{
    return `echo "$1" | awk -F"\n" '{print ($0 != $0+0)}'`
}
1
mary
printf '%b' "-123\nABC" | tr '[:space:]' '_' | grep -q '^-\?[[:digit:]]\+$' && echo "Integer." || echo "NOT integer."

Удалите -\? в шаблоне соответствия grep, если вы не принимаете отрицательное целое число.

1
Ane Dijitak

Для моей проблемы мне нужно было только убедиться, что пользователь случайно не введет какой-то текст, поэтому я старался сделать его простым и читабельным

isNumber() {
    (( $1 )) 2>/dev/null
}

Согласно справочной странице это в значительной степени делает то, что я хочу

Если значение выражения не равно нулю, возвращаемое состояние равно 0

Чтобы предотвратить неприятные сообщения об ошибках для строк, которые могут быть числами, я игнорирую вывод ошибок

$ (( 2s ))
bash: ((: 2s: value too great for base (error token is "2s")
1
Hachi

Мне нравится ответ Альберто Закканьи.

if [ "$var" -eq "$var" ] 2>/dev/null; then

Важные предварительные условия: - не было создано ни одной подоболочки - парсер RE не вызван - большинство приложений Shell не используют действительные числа

Но если $var является сложным (например, доступ к ассоциативному массиву), и если число будет неотрицательным целым числом (в большинстве случаев), то, возможно, это более эффективно?

if [ "$var" -ge 0 ] 2> /dev/null; then ..
1
user3895088

Quick & Dirty: я знаю, что это не самый элегантный способ, но я обычно просто добавляю ноль к нему и проверяю результат. вот так:

function isInteger {
  [ $(($1+0)) != 0 ] && echo "$1 is a number" || echo "$1 is not a number"
 }

x=1;      isInteger $x
x="1";    isInteger $x
x="joe";  isInteger $x
x=0x16 ;  isInteger $x
x=-32674; isInteger $x   

$ (($ 1 + 0)) вернет 0 или бомбу, если $ 1 НЕ является целым числом. например:

function zipIt  { # quick Zip - unless the 1st parameter is a number
  ERROR="not a valid number. " 
  if [ $(($1+0)) != 0 ] ; then  # isInteger($1) 
      echo " backing up files changed in the last $1 days."
      OUT="zipIt-$1-day.tgz" 
      find . -mtime -$1 -type f -print0 | xargs -0 tar cvzf $OUT 
      return 1
  fi
    showError $ERROR
}

ПРИМЕЧАНИЕ: я думаю, я никогда не думал проверять плавающие или смешанные типы, которые сделают всю скриптовую бомбу ... в моем случае я не хотел, чтобы это пошло дальше. Я собираюсь поиграть с решением mrucci и регулярным выражением Даффи - они кажутся наиболее надежными в рамках bash ... 

1
WWWIZARDS

Я использую следующее (для целых чисел):

## ##### constants
##
## __TRUE - true (0)
## __FALSE - false (1)
##
typeset -r __TRUE=0
typeset -r __FALSE=1

## --------------------------------------
## isNumber
## check if a value is an integer 
## usage: isNumber testValue 
## returns: ${__TRUE} - testValue is a number else not
##
function isNumber {
  typeset TESTVAR="$(echo "$1" | sed 's/[0-9]*//g' )"
  [ "${TESTVAR}"x = ""x ] && return ${__TRUE} || return ${__FALSE}
}

isNumber $1 
if [ $? -eq ${__TRUE} ] ; then
  print "is a number"
fi
1
Marnix

Если у вас установлен Perl, этот вкладыш прост, читабелен и расширяем

Perl -se 'exit($n !~ /\d+/)' -- -n=a

Вот несколько тестов

Perl -se 'exit($n !~ /\d+/)' -- -n=a; echo $?
1
Perl -se 'exit($n !~ /\d+/)' -- -n=2; echo $?
0

Это довольно понятно, но вот больше информации

  • -e включает оценку
  • -s разрешает передавать аргументы после - в этом случае -n
  • !~ является оператором совпадения регулярного выражения отрицания, поскольку 0 в bash - это успех, мы хотим, чтобы он успешно завершился, если аргумент -n - это число

Вы захотите обернуть это в функцию, здесь лучшая версия, которая также может читать плавающие

is_number() { Perl -se 'exit($n !~ /^\d+(\.\d+)?$/)' -- -n="$1"; }
0
geckos