Кроме того - у используемого test && echo "foo" && exit 0 || echo "bar" && exit 1вами подхода могут быть некоторые непреднамеренные побочные эффекты - если эхо не выполнится (возможно, вывод на закрытый FD), exit 0он будет пропущен, а затем попытается выполнить код echo "bar". Если и при этом &&произойдет сбой, условие не будет выполнено и даже не выполнится exit 1! Использование реальных ifутверждений, а не &&/ ||менее подвержено неожиданным побочным эффектам.
Чарльз Даффи
@CharlesDuffy Это действительно умное мышление, к которому большинство людей приходят, только когда им приходится выслеживать волосатых жуков ...! Я никогда не думал, что эхо может вернуть неудачу.
Камило Мартин
6
Немного опоздал на вечеринку, но я знаю об опасностях, о которых писал Чарльз, так как мне пришлось пережить их довольно давно. Итак, вот вам 100% надежная (и хорошо читаемая) строка для вас: [[ $1 =~ "^[0-9]+$" ]] && { echo "number"; exit 0; } || { echo "not a number"; exit 1; }фигурные скобки указывают, что вещи НЕ должны выполняться в подоболочке (что определенно будет так, если ()вместо этого использовать круглые скобки). Предостережение: никогда не пропускайте последнюю точку с запятой . В противном случае вы можете bashраспечатать самые уродливые (и самые бессмысленные) сообщения об ошибках ...
syntaxerror
5
Это не работает в Ubuntu, если вы не удалите кавычки. Так и должно быть[[ 12345 =~ ^[0-9]+$ ]] && echo OKKK || echo NOOO
Тревиньо
4
Вы должны быть более конкретными о том, что вы подразумеваете под «числом» . Целое число? Число с фиксированной точкой? Научная ("е") запись? Существует ли требуемый диапазон (например, 64-разрядное значение без знака), или вы разрешаете писать любое число?
Тоби Спейт
Ответы:
804
Один из подходов заключается в использовании регулярного выражения, например так:
re='^[0-9]+$'if![[ $yournumber =~ $re ]];then
echo "error: Not a number">&2; exit 1fi
Если значение не обязательно является целым числом, попробуйте соответствующим образом изменить регулярное выражение; например:
+1 для этого подхода, но будьте осторожны с десятичными числами, выполняя этот тест, например, с ошибкой «1.0» или «1,0»: «Не число».
sourcerebels
15
Я нашел '' exec> & 2; эхо ... '' довольно глупо. Просто '' эхо ...> & 2 ''
1
5
@Ben вы действительно хотите обрабатывать более одного знака минус? Я бы сделал это ^-?лучше, чем ^-*если вы на самом деле не выполняете работу по правильной обработке нескольких инверсий.
Чарльз Даффи
4
@SandraSchlichting Заставляет весь будущий вывод идти в stderr. Здесь нет особого смысла, когда есть только одно эхо, но это привычка, к которой я стремлюсь, в случаях, когда сообщения об ошибках занимают несколько строк.
Чарльз Даффи
29
Я не уверен, почему регулярное выражение должно быть сохранено в переменной, но если это ради совместимости, я не думаю, что это необходимо. Вы можете просто применить выражение непосредственно: [[ $yournumber =~ ^[0-9]+$ ]].
konsolebox
284
Без башмизмов (работает даже в Системе В Ш),
case $string in''|*[!0-9]*) echo bad ;;*) echo good ;;esac
Это отклоняет пустые строки и строки, содержащие не-цифры, принимая все остальное.
Отрицательные числа или числа с плавающей точкой требуют дополнительной работы. Идея состоит в том, чтобы исключить -/ .в первом «плохом» шаблоне и добавить больше «плохих» шаблонов, содержащих их ненадлежащее использование ( ?*-*/ *.*.*)
+1 - это идиоматичный, переносимый способ возврата к исходной оболочке Bourne, со встроенной поддержкой подстановочных знаков в стиле glob. Если вы пришли из другого языка программирования, это выглядит жутко, но это гораздо элегантнее, чем справляться с хрупкостью различных проблем цитирования и бесконечными проблемами обратной / боковой совместимости сif test ...
tripleee
6
Вы можете изменить первую строку на ${string#-}(которая не работает в античных оболочках Борна, но работает в любой оболочке POSIX), чтобы принимать отрицательные целые числа.
Жиль "ТАК - перестань быть злым"
4
Кроме того, это легко распространить на поплавки - просто добавьте '.' | *.*.*запрещенные шаблоны и добавьте точку к разрешенным символам. Точно так же вы можете разрешить дополнительный знак раньше, хотя тогда я предпочел case ${string#[-+]}бы просто игнорировать знак.
@Dor Кавычки не нужны, так как команда case в любом случае не выполняет разбиение слов и генерацию пути к этому слову. (Тем не менее, для расширений в случае шаблонов может потребоваться
заключить в кавычки,
193
Следующее решение также можно использовать в базовых оболочках, таких как Bourne, без необходимости использования регулярных выражений. В основном любые операции вычисления числовых значений, использующие не числа, приведут к ошибке, которая будет неявно рассматриваться как ложная в оболочке:
"$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, если у нас нет числа.
ПРЕДОСТЕРЕЖЕНИЯ (благодаря комментариям ниже):
Числа с десятичными точками не являются идентифицируются как действительные «числа»
Использование [[ ]]вместо[ ] всегда будет оцениватьtrue
Большинство небашевых оболочек всегда будет оценивать это выражение как 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")
Я все еще рекомендую это (но с переменными в кавычках, чтобы учесть пустые строки), так как результат гарантированно будет использоваться как число в Bash, несмотря ни на что.
10
21
Будьте осторожны, чтобы использовать одинарные скобки; [[ a -eq a ]]оценивается как истина (оба аргумента конвертируются в ноль)
Tgr
3
Очень хорошо! Обратите внимание, что это работает только для целого числа, а не для любого числа. Мне нужно было проверить один аргумент, который должен быть целым числом, так что это сработало хорошо:if ! [ $# -eq 1 -o "$1" -eq "$1" ] 2>/dev/null; then
haridsv
6
Я бы настоятельно рекомендовал не использовать этот метод из-за немалого числа оболочек, чьи [встроенные функции будут оценивать аргументы как арифметические. Это верно как для ksh93, так и для mksh. Кроме того, поскольку оба этих массива поддерживают, существует легкая возможность для внедрения кода. Вместо этого используйте сопоставление с образцом.
ormaaj
3
@AlbertoZaccagni, в текущих выпусках bash эти значения интерпретируются с правилами числового контекста только для, [[ ]]но не для [ ]. Тем не менее, это поведение не определено ни стандартом POSIX для, ни testв собственной документации bash; будущие версии bash могут изменить поведение, чтобы соответствовать ksh, не нарушая никаких задокументированных поведенческих обещаний, поэтому уверенность в том, что его текущее поведение сохраняется, не гарантированно безопасна.
Чарльз Даффи
43
Это проверяет, является ли число неотрицательным целым числом и является ли оно независимым от оболочки (то есть без башизмов), и использует только встроенные функции оболочки:
НЕПРАВИЛЬНО.
Поскольку этот первый ответ (ниже) допускает целые числа с символами в них, пока первые не являются первыми в переменной.
[-z "${num##[0-9]*}"]&& echo "is a number"|| echo "is not a number";
ПРАВИЛЬНО .
Как прокомментировал и предположил Джилс в своем ответе, это правильный способ сделать это, используя шаблоны оболочки.
[!-z "${num##*[!0-9]*}"]&& echo "is a number"|| echo "is not a number";
Это не работает должным образом, оно принимает любую строку, начинающуюся с цифры. Обратите внимание, что WORD в $ {VAR ## WORD} и аналогичных ему является шаблоном оболочки, а не регулярным выражением.
Джилл
2
Можете ли вы перевести это выражение на английский, пожалуйста? Я действительно хочу использовать это, но я не понимаю этого достаточно, чтобы доверять этому, даже после просмотра страницы руководства bash.
CivFan
2
*[!0-9]*это шаблон, который соответствует всем строкам, по крайней мере, с 1 нецифровым символом. ${num##*[!0-9]*}это «расширение параметра», где мы берем содержимое numпеременной и удаляем самую длинную строку, которая соответствует шаблону. Если результат раскрытия параметра не пустой ( ! [ -z ${...} ]), то это число, так как оно не содержит нецифровых символов.
Mrucci
К сожалению, это не работает, если в аргументе есть цифры, даже если это недопустимое число. Например, «exam1ple» или «a2b».
Гленн, я удалить shopt -s extglobиз вашего поста (что я upvoted, это одна из моих любимых ответов здесь), так как в условных конструктах вы можете прочитать: Когда ==и !=используются операторы, строка справа оператора считается образцом и соответствием согласно правилам, описанным ниже в Pattern Matching , как если бы extglobопция оболочки была включена. Надеюсь, ты не против!
gniourf_gniourf
В таких условиях вам не нужно shopt extglob... это хорошо знать!
gniourf_gniourf
Хорошо работает для простых целых чисел.
2
@Jdamian: вы правы, это было добавлено в Bash 4.1 (который был выпущен в конце 2009 года… Bash 3.2 был выпущен в 2006 году… теперь это античное программное обеспечение, извините за тех, кто застрял в прошлом). Кроме того, вы можете утверждать, что extglobs были введены в версии 2.02 (выпущенной в 1998 году) и не работают в версиях <2.02 ... Теперь ваш комментарий послужит предупреждением относительно более старых версий.
gniourf_gniourf
1
Переменные внутри [[...]]не подлежат разделению слов или расширению глобуса.
Гленн Джекман
26
Я удивлен решениями, непосредственно разбирающими числовые форматы в оболочке. 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» на тот формат, который вам требуется.
isnumber(){ printf '%f' "$1" &>/dev/null && echo "this is a number" || echo "not a number"; }
Жиль Квено
4
@sputnick ваша версия нарушает внутреннюю (и полезную) семантику возвращаемого значения исходной функции. Поэтому вместо этого просто оставьте функцию как есть и используйте ее:isnumber 23 && echo "this is a number" || echo "not a number"
Майкл
4
Разве это не должно иметь 2>/dev/null, чтобы isnumber "foo"не загрязнять stderr?
Джоеле
4
Называть современные оболочки, такие как bash, «DSL для управления файлами и процессами» - значит игнорировать то, что они используются для чего-то большего - некоторые дистрибутивы построили на нем целые менеджеры пакетов и веб-интерфейсы (какими бы уродливыми они ни были). Пакетные файлы соответствуют вашему описанию, хотя даже установка переменной там затруднительна.
Камило Мартин
7
Забавно, что ты пытаешься быть умным, копируя некоторые идиомы с других языков. К сожалению, это не работает в оболочках. Оболочки очень особенные, и, не зная о них, вы, скорее всего, напишите неработающий код. Ваш код не работает: isnumber "'a"вернет true. Это задокументировано в спецификации POSIX, где вы прочтете: если начальный символ - одинарная или двойная кавычка, значение должно быть числовым значением в базовом наборе кодов символа, следующего за одинарной или двойной кавычкой. ,
gniourf_gniourf
16
Я смотрел на ответы и ... понял, что никто не думал о числах FLOAT (с точкой)!
Использование grep тоже замечательно.
-E означает расширенное регулярное выражение
-q означает тихий (не повторяет)
-qE является комбинацией обоих.
Решения, использующие awk by triple_r и tripleee, работают с поплавками.
Кен Джексон
Спасибо за это и очень хороший момент! Потому что вопрос в том, как проверить, является ли это число, а не целое число.
Танасис
Я тоже благодарю вас, Танасис! Давайте помогать друг другу всегда.
Серхио Абреу
12
Просто продолжение до @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
Печать номера менее полезна, чем установка кода выхода. 'BEGIN { exit(1-(a==a+0)) }'немного трудно , но обращали внимание может быть использован в функции , которая возвращает истину или ложь так же , как [, grep -qи т.д.
tripleee
9
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
Для моей проблемы мне нужно было только убедиться, что пользователь случайно не введет какой-то текст, поэтому я старался сделать его простым и читабельным
isNumber(){(( $1 ))2>/dev/null
}
Согласно справочной странице это в значительной степени делает то, что я хочу
Если значение выражения не равно нулю, возвращаемое состояние равно 0
Чтобы предотвратить неприятные сообщения об ошибках для строк, которые могут быть числами, я игнорирую вывод ошибок
$ ((2s))
bash:((:2s: value too great for base (error token is "2s")
Это больше похоже на isInteger. Но здорово, спасибо!
Нахил
8
Старый вопрос, но я просто хотел придерживаться своего решения. Этот не требует каких-либо странных трюков с оболочкой или полагается на то, чего не было всегда.
if[-n "$(printf '%s\n' "$var" | sed 's/[0-9]//g')"];then
echo 'is not numeric'else
echo 'is numeric'fi
По сути, он просто удаляет все цифры из входных данных, и если у вас останется строка не нулевой длины, тогда это не число.
Или для переменных с завершающими символами новой строки или что-то в этом роде $'0\n\n\n1\n\n\n2\n\n\n3\n'.
gniourf_gniourf
7
Пока не могу комментировать, поэтому я добавлю свой собственный ответ, который является расширением ответа Гленна Джекмана с использованием сопоставления с шаблоном 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}"donefor 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)). Мои модульные тесты тестируют только значения, которые являются целочисленными или плавающими, но не содержат недопустимых входных данных.
или дубликат, или, возможно, лучше подходит как комментарий к ответу pixelbeat (в %fлюбом случае лучше использовать)
Майкл
3
Вместо того, чтобы проверять предыдущий код состояния, почему бы просто не поместить его в ifсебя? Вот что ifзначит ...if printf "%g" "$var" &> /dev/null; then ...
Камило Мартин
3
Это имеет другие предостережения. Это проверит пустую строку и строки вроде 'a.
gniourf_gniourf
6
Четкий ответ уже дали @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
Хотя для действительных чисел не обязательно иметь число перед точкой ось .
Чтобы обеспечить более полную поддержку плавающих чисел и научных обозначений (многие программы на 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, которые, кажется, удерживают:
Какая минимальная версия bash? Я просто получаю bash: условный двоичный оператор, ожидаемый bash: синтаксическая ошибка рядом с неожиданным токеном `= ~ '
Пол Харгривз
1
@PaulHargreaves =~существовал по крайней мере еще в bash 3.0.
Жиль "ТАК ... перестать быть злым"
@PaulHargreaves, что у вас, вероятно, была проблема с вашим первым операндом, например, слишком много кавычек или тому подобное
Джошуа Клейтон,
@JoshuaClayton Я спросил о версии, потому что это очень старая версия bash для Solaris 7, которую мы до сих пор имеем и не поддерживаем = ~
Пол Харгривз
6
Это может быть достигнуто с помощью grepпроверки соответствия рассматриваемой переменной расширенному регулярному выражению.
Тест целое число 1120:
yournumber=1120if echo "$yournumber"| grep -qE '^[0-9]+$';then
echo "Valid number."else
echo "Error: not a number."fi
Вывод: Valid number.
Тест не целое число 1120a:
yournumber=1120aif echo "$yournumber"| grep -qE '^[0-9]+$';then
echo "Valid number."else
echo "Error: not a number."fi
Вывод: Error: not a number.
объяснение
grep, То -Eпереключатель позволяет использовать расширенные регулярные выражения '^[0-9]+$'. Это регулярное выражение означает, что переменная должна []содержать только цифры от 0-9нуля до девяти от ^начала до $конца переменной и должна иметь хотя бы +один символ.
grep, То-q переключатель тихо отключает любой выход находит ли он или нет ничего.
ifпроверяет статус выхода grep. Статус выхода 0означает успех, а что-либо большее означает ошибку. Команда grepимеет статус выхода, 0если она находит совпадение, а 1когда нет;
Таким образом, помещая все вместе, в ifтест, мы echoпеременную $yournumberи передаем по |ней, grepс помощью -qпереключателя молча соответствует -Eрасширенное выражение регулярного '^[0-9]+$'выражения. Статус выхода grepбудет, 0если grepуспешно найдено совпадение и 1если нет. Если удалось совпадать, мы echo "Valid number.". Если это не соответствует, мы echo "Error: not a number.".
Для поплавков или пар
Мы можем просто изменить регулярное выражение с '^[0-9]+$'на '^[0-9]*\.?[0-9]+$'для float или double.
Тест поплавок 1120.01:
yournumber=1120.01if echo "$yournumber"| grep -qE '^[0-9]*\.?[0-9]+$';then
echo "Valid number."else
echo "Error: not a number."fi
Вывод: Valid number.
Тест поплавок 11.20.01:
yournumber=11.20.01if echo "$yournumber"| grep -qE '^[0-9]*\.?[0-9]+$';then
echo "Valid number."else
echo "Error: not a number."fi
Вывод: Error: not a number.
Для негативов
Чтобы разрешить отрицательные целые числа, просто измените регулярное выражение с '^[0-9]+$'на '^\-?[0-9]+$'.
Чтобы разрешить отрицательные числа с плавающей запятой или двойные числа, просто измените регулярное выражение с '^[0-9]*\.?[0-9]+$'на '^\-?[0-9]*\.?[0-9]+$'.
LGTM; Ответ отредактирован имеет +1. Единственные вещи, которые я бы сделал по-другому на данном этапе, это просто вопросы мнения, а не правильности (f / e, использование [-]вместо \-и [.]вместо \.немного более многословно, но это означает, что ваши строки не должны изменяться, если они ' используется в контексте, где обратные слеши потребляются).
Вы также можете использовать классы персонажей bash.
if[[ $VAR =*[[:digit:]]*]];then
echo "$VAR is numeric"else
echo "$VAR is not numeric"fi
Числа включают пробел, десятичную точку и «е» или «Е» для числа с плавающей запятой.
Но если вы укажете шестнадцатеричное число в стиле 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
[[ $VAR = *[[:digit:]]* ]]возвращает истину , если переменная содержит число, только если это не является целым числом.
Гленн Джекман
[[ "z3*&" = *[[:digit:]]* ]] && echo "numeric"отпечатки numeric. Протестировано в Bash версии 3.2.25(1)-release.
Jdamian
1
@ultraswadable, ваше решение обнаруживает строки, содержащие, по крайней мере, одну цифру, окруженную (или нет) любыми другими символами. Я понизил.
Дждамян
Поэтому очевидно правильный подход состоит в том, чтобы обратить это вспять и использовать[[ -n $VAR && $VAR != *[^[:digit:]]* ]]
eschwartz
@eschwartz, ваше решение не работает с отрицательными числами
Angel
4
Самый простой способ - проверить, содержит ли он нецифровые символы. Вы заменяете все цифры на ничто и проверяете длину. Если есть длина, это не число.
if[[!-n ${input//[0-9]/}]];then
echo "Input Is A Number"fi
Для обработки отрицательных чисел потребуется более сложный подход.
Энди
... или необязательный положительный знак.
tripleee
@tripleee Я хотел бы увидеть ваш подход, если вы знаете, как это сделать.
Энди
4
Поскольку в последнее время мне приходилось вмешиваться в это, и мне больше всего нравился подход Картту с модульным тестом. Я пересмотрел код и добавил некоторые другие решения, попробуйте сами, чтобы увидеть результаты:
Поэтому isNumber () включает в себя тире, запятые и экспоненциальные обозначения и поэтому возвращает TRUE для целых чисел и чисел с плавающей запятой, тогда как isFloat () возвращает FALSE для целочисленных значений, а isInteger () аналогичным образом возвращает FALSE для чисел с плавающей запятой. Для вашего удобства все как один лайнер:
Лично я удалил бы functionключевое слово, поскольку оно не делает ничего полезного. Кроме того, я не уверен насчет полезности возвращаемых значений. Если не указано иное, функции будут возвращать состояние выхода последней команды, поэтому вам ничего не нужно returnсамостоятельно.
Том Фенек
Хорошо, действительно, returnони сбивают с толку и делают его менее читабельным. Использование functionключевых слов или нет - это больше вопрос личного вкуса, по крайней мере, я убрал их из одних строк, чтобы сэкономить место. Спасибо.
3ronco
Не забывайте, что точки с запятой нужны после тестов для однострочных версий.
Том Фенек
2
isNumber вернет 'true' для любой строки, в которой есть число.
DrStrangepork
@DrStrangepork Действительно, в моем массиве false_values отсутствует этот случай. Я буду смотреть на это. Спасибо за подсказку.
3ronco
4
Я использую expr . Он возвращает ненулевое значение, если вы пытаетесь добавить ноль к нечисловому значению:
if expr --"$number"+0>/dev/null 2>&1then
echo "$number is a number"else
echo "$number isn't a number"fi
Возможно, можно использовать bc, если вам нужны нецелые числа, но я не верю, что bcведет себя точно так же. Добавление нуля к нечисленному номеру возвращает вас к нулю и возвращает также нулевое значение. Может быть, вы можете объединить bcи expr. Используйте, bcчтобы добавить ноль к $number. Если ответ 0, то попробуйте exprпроверить, что $numberэто не ноль.
Это довольно плохо. Чтобы сделать это немного лучше, вы должны использовать expr -- "$number" + 0; все же это все еще притворится 0 isn't a number. От man expr:Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null or 0,
gniourf_gniourf
3
Мне нравится ответ Альберто Закканьи.
if["$var"-eq "$var"]2>/dev/null;then
Важные предварительные условия: - не создаются подоболочки - не запускаются парсеры RE - большинство приложений оболочки не используют реальные числа
Но если $varэто сложно (например, доступ к ассоциативному массиву), и если число будет неотрицательным целым числом (в большинстве случаев), то, возможно, это более эффективно?
Я использую 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=1local-i FAIL=0case"${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; }
ударрегулярное выражение противударрасширение параметра
Как работают ответы Чарльза Даффи , но используют толькоударрегулярное выражение , и я знаю, что это медленно, я хотел бы показать другой способ, используя толькоударрасширение параметра :
set--"foo bar"
is_num "$1"&& VAR=$1 || echo "need a number"
need a number
set--"+3.141592"
is_num "$1"&& VAR=$1 || echo "need a number"
echo $VAR
+3.141592
if is_num foo;then echo It\'s a number ;else echo Not a number;fiNot a number
if cdIs_num foo;then echo It\'s a number ;else echo Not a number;fiNot a number
if is_num 25;then echo It\'s a number ;else echo Not a number;fiIt's a number
if cdIs_num 25;then echo It\'s a number ;else echo Not a number;fi
It's a number
if is_num 3+4;then echo It\'s a number ;else echo Not a number;fiNot a number
if cdIs_num 3+4;then echo It\'s a number ;else echo Not a number;fiNot a number
if is_num 3.1415;then echo It\'s a number ;else echo Not a number;fiIt's a number
if cdIs_num 3.1415;then echo It\'s a number ;else echo Not a number;fi
It's a number
Хорошо, это нормально. Теперь сколько времени займет все это (на моем малиновом пи):
time for i in{1..1000};do is_num +3.14159265;done
real 0m2.476s
user 0m1.235s
sys 0m0.000s
Тогда с регулярными выражениями:
time for i in{1..1000};do cdIs_num +3.14159265;done
real 0m4.363s
user 0m2.168s
sys 0m0.000s
Я согласен, во всяком случае, я предпочитаю не использовать регулярные выражения, когда я мог бы использовать расширение параметров ... Злоупотребление RE замедлит сценарий bash
Ф. Хаури
Отредактированный ответ: Нет необходимости extglob(и немного быстрее)!
Ф. Хаури
@CharlesDuffy, На моем Raspberry Pi 1000 итераций займут 2,5 секунды в моей версии и 4,4 секунды в вашей версии!
Ф. Хаури
С этим не поспоришь. Charles
Чарльз Даффи
1
Чтобы поймать отрицательные числа:
if[[ $1 ==?(-)+([0-9.])]]then
echo number
else
echo not a number
fi
Кроме того, для этого необходимо сначала включить расширенную глобализацию. Это функция только для Bash, которая по умолчанию отключена.
tripleee
Расширенное глобирование @tripleee активируется автоматически при использовании == или! = When the ‘==’ and ‘!=’ operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled.gnu.org/software/bash/manual/bashref.html#index-_005b_005b
Бадр Элмерс
@BadrElmers Спасибо за обновление. Кажется, это новое поведение, которое не соответствует действительности в моем Bash 3.2.57 (MacOS Mojave). Я вижу, что это работает, как вы описали в 4.4.
трипл
1
Вы можете использовать «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+, как некоторые ответы в этой теме.
Даунвот за отсутствие объяснений. Как это работает? Он выглядит сложным и хрупким, и неясно, какие именно данные он примет. (Например, действительно ли необходимо удалить пробелы? Почему? Он скажет, что число со встроенными пробелами является допустимым числом, что может быть нежелательно.)
tripleee
1
Сделали то же самое здесь с регулярным выражением, которое проверяет всю часть и десятичную часть, разделенные точкой.
Не могли бы вы объяснить, почему ваш ответ в корне отличается от других старых ответов, например, ответа Чарльза Даффи? Ну, ваш ответ на самом деле не работает, поскольку он проверяет один период.
gniourf_gniourf
Я не уверен, что понимаю единственный период здесь ... это один или нулевой период, ожидаемый .... Но верно, ничего принципиально иного, просто нашел регулярное выражение легче для чтения.
Джером
также использование * должно соответствовать большему количеству реальных случаев
Джером
Дело в том, что вы сопоставляете пустую строку a=''и строку, содержащую только точку, a='.'поэтому ваш код немного сломан ...
gniourf_gniourf
0
Я использую следующее (для целых чисел):
## ##### 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
Почти правильно (вы принимаете пустую строку), но излишне сложно до такой степени запутывать.
Жиль "ТАК - перестань быть злым"
2
Неправильно: вы принимаете -nи т. Д. (Из-за echo), и вы принимаете переменные с завершающими символами новой строки (из-за $(...)). И, кстати, printне является допустимой командой оболочки.
gniourf_gniourf
0
Я попробовал рецепт ультразвука, так как он показался мне наиболее практичным, и не смог заставить его работать. В конце концов я разработал другой способ, основанный, как и другие, на подстановке параметров, на этот раз с заменой регулярного выражения:
[["${var//*([[:digit:]])}"]];&& echo "$var is not numeric"|| echo "$var is numeric"
Он удаляет каждый символ: digit: class в $ var и проверяет, остались ли у нас пустые строки, что означает, что оригинал был только числами.
Что мне нравится в этом, так это его небольшой размер и гибкость. В этой форме он работает только для целых 10 без разделителей, хотя, безусловно, вы можете использовать сопоставление с образцом, чтобы удовлетворить его другим потребностям.
Читая решение mrucci, оно выглядит почти так же, как мое, но с использованием обычной замены строк вместо «стиля sed». Оба используют одинаковые правила для сопоставления с образцом и, AFAIK, являются взаимозаменяемыми решениями.
ата
sedэто POSIX, а ваше решение есть bash. Оба имеют свое применение
v010dya
0
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
return1fi
showError $ERROR
}
ПРИМЕЧАНИЕ: я думаю, я никогда не думал проверять поплавки или смешанные типы, которые сделают всю скриптовую бомбу ... в моем случае я не хотел, чтобы это пошло дальше. Я собираюсь поиграть с решением mrucci и регулярным выражением Даффи - они кажутся наиболее надежными в рамках bash ...
Это принимает арифметические выражения как 1+1, но отклоняет некоторые натуральные числа с ведущими 0s (потому что 08это недопустимая восьмеричная константа).
Жиль "ТАК - перестань быть злым"
2
Это и другие вопросы тоже: 0не число, и оно подлежит произвольному инъекции коды, попробуйте: isInteger 'a[$(ls)]'. По электронной почте Ой.
gniourf_gniourf
1
И расширение не заключено $((...))в кавычки, число IFS=123изменит его.
test && echo "foo" && exit 0 || echo "bar" && exit 1
вами подхода могут быть некоторые непреднамеренные побочные эффекты - если эхо не выполнится (возможно, вывод на закрытый FD),exit 0
он будет пропущен, а затем попытается выполнить кодecho "bar"
. Если и при этом&&
произойдет сбой, условие не будет выполнено и даже не выполнитсяexit 1
! Использование реальныхif
утверждений, а не&&
/||
менее подвержено неожиданным побочным эффектам.[[ $1 =~ "^[0-9]+$" ]] && { echo "number"; exit 0; } || { echo "not a number"; exit 1; }
фигурные скобки указывают, что вещи НЕ должны выполняться в подоболочке (что определенно будет так, если()
вместо этого использовать круглые скобки). Предостережение: никогда не пропускайте последнюю точку с запятой . В противном случае вы можетеbash
распечатать самые уродливые (и самые бессмысленные) сообщения об ошибках ...[[ 12345 =~ ^[0-9]+$ ]] && echo OKKK || echo NOOO
Ответы:
Один из подходов заключается в использовании регулярного выражения, например так:
Если значение не обязательно является целым числом, попробуйте соответствующим образом изменить регулярное выражение; например:
... или для обработки чисел со знаком:
источник
^-?
лучше, чем^-*
если вы на самом деле не выполняете работу по правильной обработке нескольких инверсий.[[ $yournumber =~ ^[0-9]+$ ]]
.Без башмизмов (работает даже в Системе В Ш),
Это отклоняет пустые строки и строки, содержащие не-цифры, принимая все остальное.
Отрицательные числа или числа с плавающей точкой требуют дополнительной работы. Идея состоит в том, чтобы исключить
-
/.
в первом «плохом» шаблоне и добавить больше «плохих» шаблонов, содержащих их ненадлежащее использование (?*-*
/*.*.*
)источник
if test ...
${string#-}
(которая не работает в античных оболочках Борна, но работает в любой оболочке POSIX), чтобы принимать отрицательные целые числа.'.' | *.*.*
запрещенные шаблоны и добавьте точку к разрешенным символам. Точно так же вы можете разрешить дополнительный знак раньше, хотя тогда я предпочелcase ${string#[-+]}
бы просто игнорировать знак.Следующее решение также можно использовать в базовых оболочках, таких как Bourne, без необходимости использования регулярных выражений. В основном любые операции вычисления числовых значений, использующие не числа, приведут к ошибке, которая будет неявно рассматриваться как ложная в оболочке:
как в:
Вы можете также проверить на $? код возврата операции, которая является более явной:
Перенаправление стандартной ошибки предназначено для того, чтобы скрыть сообщение «ожидается целочисленное выражение», которое распечатывает bash, если у нас нет числа.
ПРЕДОСТЕРЕЖЕНИЯ (благодаря комментариям ниже):
[[ ]]
вместо[ ]
всегда будет оцениватьtrue
true
bash: [[: 1 a: syntax error in expression (error token is "a")
bash: [[: i: expression recursion level exceeded (error token is "i")
источник
[[ a -eq a ]]
оценивается как истина (оба аргумента конвертируются в ноль)if ! [ $# -eq 1 -o "$1" -eq "$1" ] 2>/dev/null; then
[
встроенные функции будут оценивать аргументы как арифметические. Это верно как для ksh93, так и для mksh. Кроме того, поскольку оба этих массива поддерживают, существует легкая возможность для внедрения кода. Вместо этого используйте сопоставление с образцом.[[ ]]
но не для[ ]
. Тем не менее, это поведение не определено ни стандартом POSIX для, ниtest
в собственной документации bash; будущие версии bash могут изменить поведение, чтобы соответствовать ksh, не нарушая никаких задокументированных поведенческих обещаний, поэтому уверенность в том, что его текущее поведение сохраняется, не гарантированно безопасна.Это проверяет, является ли число неотрицательным целым числом и является ли оно независимым от оболочки (то есть без башизмов), и использует только встроенные функции оболочки:
НЕПРАВИЛЬНО.
Поскольку этот первый ответ (ниже) допускает целые числа с символами в них, пока первые не являются первыми в переменной.
ПРАВИЛЬНО .
Как прокомментировал и предположил Джилс в своем ответе, это правильный способ сделать это, используя шаблоны оболочки.
источник
*[!0-9]*
это шаблон, который соответствует всем строкам, по крайней мере, с 1 нецифровым символом.${num##*[!0-9]*}
это «расширение параметра», где мы берем содержимоеnum
переменной и удаляем самую длинную строку, которая соответствует шаблону. Если результат раскрытия параметра не пустой (! [ -z ${...} ]
), то это число, так как оно не содержит нецифровых символов.122s
:-(
Никто не предложил расширенное сопоставление с образцом в bash :
источник
shopt -s extglob
из вашего поста (что я upvoted, это одна из моих любимых ответов здесь), так как в условных конструктах вы можете прочитать: Когда==
и!=
используются операторы, строка справа оператора считается образцом и соответствием согласно правилам, описанным ниже в Pattern Matching , как если быextglob
опция оболочки была включена. Надеюсь, ты не против!shopt extglob
... это хорошо знать![[...]]
не подлежат разделению слов или расширению глобуса.Я удивлен решениями, непосредственно разбирающими числовые форматы в оболочке. shell не очень подходит для этого, поскольку является DSL для управления файлами и процессами. Немного ниже парсеры чисел, например:
Измените «% f» на тот формат, который вам требуется.
источник
isnumber(){ printf '%f' "$1" &>/dev/null && echo "this is a number" || echo "not a number"; }
isnumber 23 && echo "this is a number" || echo "not a number"
2>/dev/null
, чтобыisnumber "foo"
не загрязнять stderr?isnumber "'a"
вернет true. Это задокументировано в спецификации POSIX, где вы прочтете: если начальный символ - одинарная или двойная кавычка, значение должно быть числовым значением в базовом наборе кодов символа, следующего за одинарной или двойной кавычкой. ,Я смотрел на ответы и ... понял, что никто не думал о числах FLOAT (с точкой)!
Использование grep тоже замечательно.
-E означает расширенное регулярное выражение
-q означает тихий (не повторяет)
-qE является комбинацией обоих.
Чтобы проверить прямо в командной строке:
Использование в скрипте bash:
Чтобы соответствовать JUST целым числам, используйте это:
источник
Просто продолжение до @mary. Но из-за того, что у меня недостаточно представителей, я не смог опубликовать это как комментарий к этому сообщению. В любом случае, вот что я использовал:
Функция вернет «1», если аргумент является числом, в противном случае вернет «0». Это работает как для целых чисел, так и для чисел с плавающей точкой. Использование это что-то вроде:
источник
'BEGIN { exit(1-(a==a+0)) }'
немного трудно , но обращали внимание может быть использован в функции , которая возвращает истину или ложь так же , как[
,grep -q
и т.д.${i//[0-9]}
заменяет любую цифру в значении$i
пустой строкой, смman -P 'less +/parameter\/' bash
.-z
проверяет, имеет ли полученная строка нулевую длину.если вы также хотите исключить случай, когда
$i
пусто, вы можете использовать одну из следующих конструкций:источник
man -P 'less +/parameter\/' bash
части. Узнавать что-то новое каждый день. :)\-
регулярное выражение для решения проблемы. Используйте[0-9\-\.\+]
для учета поплавков и подписанных номеров.echo $i | python -c $'import sys\ntry:\n float(sys.stdin.read().rstrip())\nexcept:\n sys.exit(1)' && echo yes || echo no
Для моей проблемы мне нужно было только убедиться, что пользователь случайно не введет какой-то текст, поэтому я старался сделать его простым и читабельным
Согласно справочной странице это в значительной степени делает то, что я хочу
Чтобы предотвратить неприятные сообщения об ошибках для строк, которые могут быть числами, я игнорирую вывод ошибок
источник
Старый вопрос, но я просто хотел придерживаться своего решения. Этот не требует каких-либо странных трюков с оболочкой или полагается на то, чего не было всегда.
По сути, он просто удаляет все цифры из входных данных, и если у вас останется строка не нулевой длины, тогда это не число.
источник
var
.$'0\n\n\n1\n\n\n2\n\n\n3\n'
.Пока не могу комментировать, поэтому я добавлю свой собственный ответ, который является расширением ответа Гленна Джекмана с использованием сопоставления с шаблоном bash.
Моей первоначальной потребностью было идентифицировать числа и различать целые числа и числа с плавающей запятой. Определения функций вычитаются в:
Я использовал модульное тестирование (с shUnit2), чтобы проверить, что мои шаблоны работают так, как задумано:
Примечания: Шаблон isFloat можно изменить, чтобы он был более терпимым в отношении десятичной точки (
@(.,)
) и символа E (@(Ee)
). Мои модульные тесты тестируют только значения, которые являются целочисленными или плавающими, но не содержат недопустимых входных данных.источник
Я бы попробовал это:
Примечание: это распознает nan и inf как число.
источник
%f
любом случае лучше использовать)if
себя? Вот чтоif
значит ...if printf "%g" "$var" &> /dev/null; then ...
'a
.Четкий ответ уже дали @charles Dufy и другие. Чистое решение Bash будет использовать следующее:
Хотя для действительных чисел не обязательно иметь число перед точкой ось .
Чтобы обеспечить более полную поддержку плавающих чисел и научных обозначений (многие программы на C / Fortran или иначе будут экспортировать float таким способом), полезным дополнением к этой строке будет следующее:
Таким образом, можно найти способ различать типы чисел, если вы ищете какой-либо конкретный тип:
Примечание: мы могли бы перечислить синтаксические требования для десятичной и научной нотации, одна из которых заключается в том, чтобы использовать запятую как точку отсчета, а также ".". Мы бы тогда утверждали, что должна быть только одна такая точка радиуса. В плавающем [Ee] может быть два знака +/-. Я узнал еще несколько правил из работы Аулу и проверил на наличие плохих строк, таких как '' '-' '-E-1' '0-0'. Вот мои инструменты regex / substring / expr, которые, кажется, удерживают:
источник
Не забудьте
-
включить отрицательные числа!источник
=~
существовал по крайней мере еще в bash 3.0.Это может быть достигнуто с помощью
grep
проверки соответствия рассматриваемой переменной расширенному регулярному выражению.Тест целое число
1120
:Вывод:
Valid number.
Тест не целое число
1120a
:Вывод:
Error: not a number.
объяснение
grep
, То-E
переключатель позволяет использовать расширенные регулярные выражения'^[0-9]+$'
. Это регулярное выражение означает, что переменная должна[]
содержать только цифры от0-9
нуля до девяти от^
начала до$
конца переменной и должна иметь хотя бы+
один символ.grep
, То-q
переключатель тихо отключает любой выход находит ли он или нет ничего.if
проверяет статус выходаgrep
. Статус выхода0
означает успех, а что-либо большее означает ошибку. Командаgrep
имеет статус выхода,0
если она находит совпадение, а1
когда нет;Таким образом, помещая все вместе, в
if
тест, мыecho
переменную$yournumber
и передаем по|
ней,grep
с помощью-q
переключателя молча соответствует-E
расширенное выражение регулярного'^[0-9]+$'
выражения. Статус выходаgrep
будет,0
еслиgrep
успешно найдено совпадение и1
если нет. Если удалось совпадать, мыecho "Valid number."
. Если это не соответствует, мыecho "Error: not a number."
.Для поплавков или пар
Мы можем просто изменить регулярное выражение с
'^[0-9]+$'
на'^[0-9]*\.?[0-9]+$'
для float или double.Тест поплавок
1120.01
:Вывод:
Valid number.
Тест поплавок
11.20.01
:Вывод:
Error: not a number.
Для негативов
Чтобы разрешить отрицательные целые числа, просто измените регулярное выражение с
'^[0-9]+$'
на'^\-?[0-9]+$'
.Чтобы разрешить отрицательные числа с плавающей запятой или двойные числа, просто измените регулярное выражение с
'^[0-9]*\.?[0-9]+$'
на'^\-?[0-9]*\.?[0-9]+$'
.источник
[-]
вместо\-
и[.]
вместо\.
немного более многословно, но это означает, что ваши строки не должны изменяться, если они ' используется в контексте, где обратные слеши потребляются).http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html
Вы также можете использовать классы персонажей bash.
Числа включают пробел, десятичную точку и «е» или «Е» для числа с плавающей запятой.
Но если вы укажете шестнадцатеричное число в стиле C, то есть «0xffff» или «0XFFFF», [[: digit:]] вернет true. Здесь есть небольшая ловушка, bash позволяет вам делать что-то вроде «0xAZ00» и при этом считать его цифрой (разве это не странная причуда компиляторов GCC, позволяющих использовать нотацию 0x для баз, отличных от 16 ??? )
Возможно, вы захотите проверить «0x» или «0X» перед проверкой, является ли оно числовым, если ваш ввод абсолютно ненадежен, если вы не хотите принимать шестнадцатеричные числа. Это будет достигнуто путем:
источник
[[ $VAR = *[[:digit:]]* ]]
возвращает истину , если переменная содержит число, только если это не является целым числом.[[ "z3*&" = *[[:digit:]]* ]] && echo "numeric"
отпечаткиnumeric
. Протестировано в Bash версии3.2.25(1)-release
.[[ -n $VAR && $VAR != *[^[:digit:]]* ]]
Самый простой способ - проверить, содержит ли он нецифровые символы. Вы заменяете все цифры на ничто и проверяете длину. Если есть длина, это не число.
источник
Поскольку в последнее время мне приходилось вмешиваться в это, и мне больше всего нравился подход Картту с модульным тестом. Я пересмотрел код и добавил некоторые другие решения, попробуйте сами, чтобы увидеть результаты:
Поэтому isNumber () включает в себя тире, запятые и экспоненциальные обозначения и поэтому возвращает TRUE для целых чисел и чисел с плавающей запятой, тогда как isFloat () возвращает FALSE для целочисленных значений, а isInteger () аналогичным образом возвращает FALSE для чисел с плавающей запятой. Для вашего удобства все как один лайнер:
источник
function
ключевое слово, поскольку оно не делает ничего полезного. Кроме того, я не уверен насчет полезности возвращаемых значений. Если не указано иное, функции будут возвращать состояние выхода последней команды, поэтому вам ничего не нужноreturn
самостоятельно.return
они сбивают с толку и делают его менее читабельным. Использованиеfunction
ключевых слов или нет - это больше вопрос личного вкуса, по крайней мере, я убрал их из одних строк, чтобы сэкономить место. Спасибо.Я использую expr . Он возвращает ненулевое значение, если вы пытаетесь добавить ноль к нечисловому значению:
Возможно, можно использовать bc, если вам нужны нецелые числа, но я не верю, что
bc
ведет себя точно так же. Добавление нуля к нечисленному номеру возвращает вас к нулю и возвращает также нулевое значение. Может быть, вы можете объединитьbc
иexpr
. Используйте,bc
чтобы добавить ноль к$number
. Если ответ0
, то попробуйтеexpr
проверить, что$number
это не ноль.источник
expr -- "$number" + 0
; все же это все еще притворится0 isn't a number
. Отman expr
:Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null or 0,
Мне нравится ответ Альберто Закканьи.
Важные предварительные условия: - не создаются подоболочки - не запускаются парсеры RE - большинство приложений оболочки не используют реальные числа
Но если
$var
это сложно (например, доступ к ассоциативному массиву), и если число будет неотрицательным целым числом (в большинстве случаев), то, возможно, это более эффективно?источник
Я использую printf в качестве других упомянутых ответов, если вы предоставите строку формата "% f" или "% i", printf выполнит проверку за вас. Синтаксис проще, чем изобретать чеки, и он короток, а printf вездесущ. Так что, на мой взгляд, это достойный выбор - вы также можете использовать следующую идею для проверки ряда вещей, она полезна не только для проверки чисел.
>$ var=45
>$ (($(check_number $var "${CHECK_INTEGER}" "Error: Found $var - An integer is required."))) && { echo "$var+5" | bc; }
источник
удар регулярное выражение противудар расширение параметра
Как работают ответы Чарльза Даффи , но используют толькоударрегулярное выражение , и я знаю, что это медленно, я хотел бы показать другой способ, используя толькоударрасширение параметра :
Только для натуральных чисел:
Для целых чисел:
Тогда для плавания:
Чтобы соответствовать первоначальному запросу:
Теперь небольшое сравнение:
Та же проверка основана на ответе Чарльза Даффи :
Некоторые тесты:
Хорошо, это нормально. Теперь сколько времени займет все это (на моем малиновом пи):
Тогда с регулярными выражениями:
источник
extglob
(и немного быстрее)!Чтобы поймать отрицательные числа:
источник
When the ‘==’ and ‘!=’ operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled.
gnu.org/software/bash/manual/bashref.html#index-_005b_005bВы можете использовать «let» тоже так:
Но я предпочитаю использовать оператор "= ~" Bash 3+, как некоторые ответы в этой теме.
источник
Удалите
-\?
шаблон сопоставления in grep, если вы не принимаете отрицательное целое число.источник
Сделали то же самое здесь с регулярным выражением, которое проверяет всю часть и десятичную часть, разделенные точкой.
источник
.
a=''
и строку, содержащую только точку,a='.'
поэтому ваш код немного сломан ...Я использую следующее (для целых чисел):
источник
-n
и т. Д. (Из-заecho
), и вы принимаете переменные с завершающими символами новой строки (из-за$(...)
). И, кстати,print
не является допустимой командой оболочки.Я попробовал рецепт ультразвука, так как он показался мне наиболее практичным, и не смог заставить его работать. В конце концов я разработал другой способ, основанный, как и другие, на подстановке параметров, на этот раз с заменой регулярного выражения:
Он удаляет каждый символ: digit: class в $ var и проверяет, остались ли у нас пустые строки, что означает, что оригинал был только числами.
Что мне нравится в этом, так это его небольшой размер и гибкость. В этой форме он работает только для целых 10 без разделителей, хотя, безусловно, вы можете использовать сопоставление с образцом, чтобы удовлетворить его другим потребностям.
источник
sed
это POSIX, а ваше решение естьbash
. Оба имеют свое применениеQuick & Dirty: я знаю, что это не самый элегантный способ, но я обычно просто добавляю ноль к нему и проверяю результат. вот так:
$ (($ 1 + 0)) вернет 0 или бомбу, если $ 1 НЕ является целым числом. например:
ПРИМЕЧАНИЕ: я думаю, я никогда не думал проверять поплавки или смешанные типы, которые сделают всю скриптовую бомбу ... в моем случае я не хотел, чтобы это пошло дальше. Я собираюсь поиграть с решением mrucci и регулярным выражением Даффи - они кажутся наиболее надежными в рамках bash ...
источник
1+1
, но отклоняет некоторые натуральные числа с ведущими0
s (потому что08
это недопустимая восьмеричная константа).0
не число, и оно подлежит произвольному инъекции коды, попробуйте:isInteger 'a[$(ls)]'
. По электронной почте Ой.$((...))
в кавычки, числоIFS=123
изменит его.