Я просто не могу понять, как я могу убедиться, что аргумент, переданный моему script, является числом или нет.
Все, что я хочу сделать, это что-то вроде этого:
test *isnumber* $1 && VAR=$1 || echo "need a number"
Любая помощь?
Один из подходов заключается в использовании регулярного выражения, например, так:
re='^[0-9]+$'
if ! [[ $yournumber =~ $re ]] ; then
echo "error: Not a number" >&2; exit 1
fi
Если значение не обязательно является целым числом, попробуйте соответствующим образом изменить регулярное выражение; например:
^[0-9]+([.][0-9]+)?$
... или для обработки чисел со знаком:
^[+-]?[0-9]+([.][0-9]+)?$
Без багизмов (работает даже в System V sh),
case $string in
''|*[!0-9]*) echo bad ;;
*) echo good ;;
esac
Это отклоняет пустые строки и строки, содержащие не-цифры, принимая все остальное.
Отрицательные или плавающие числа нуждаются в дополнительной работе. Идея состоит в том, чтобы исключить -
/.
в первом "плохом" шаблоне и добавить более "плохие" шаблоны, содержащие их неправильное использование (?*-*
/*.*.*
)
if test ...
${string#-}
(которая не работает в античных оболочках Борна, но работает в любой оболочке POSIX), чтобы принимать отрицательные целые числа.
Следующее решение может также использоваться в базовых оболочках, таких как 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: syntax error in expression (error token is "a")
bash: [[: i: expression recursion level exceeded (error token is "i")
[[ a -eq a ]]
оценивается как true (оба аргумента конвертируются в ноль)
Это проверяет, является ли число неотрицательным целым и не зависит от оболочки (т.е. без багизмов) и использует только встроенные оболочки:
[ -z "${num##[0-9]*}" ] && echo "is a number" || echo "is not a number";
НО НЕПРАВИЛЬНО.
Поскольку jilles прокомментировал и предложил в его ответ, это правильный способ сделать это с использованием shell-шаблонов.
[ ! -z "${num##*[!0-9]*}" ] && echo "is a number" || echo "is not a number";
Никто не предложил bash расширенное сопоставление образцов:
[[ $1 == ?(-)+([0-9]) ]] && echo "$1 is an integer"
shopt -s extglob
из твоего поста (за который я проголосовал, это один из моих любимых ответов здесь), так как в Условных конструкциях ты можешь читать: Когда используются операторы ==
и !=
, Строка справа от оператор считается шаблоном и сопоставляется в соответствии с правилами, описанными ниже в extglob
Сопоставление шаблонов» , как если бы была extglob
опция оболочки extglob
. Надеюсь, ты не против!
shopt extglob
... это хорошо знать!
Я удивляюсь решениям, которые непосредственно обрабатывают форматы чисел в оболочке. 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"; }
Я смотрел ответы и... понял, что никто не думал о числах 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 script:
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]+$`
Просто следуйте за @mary. Но, поскольку мне не хватает репутации, я не могу опубликовать это как комментарий к этому сообщению. В любом случае, вот что я использовал:
isnum() { awk -v a="$1" 'BEGIN {print (a == a + 0)}'; }
Функция вернет "1", если аргумент будет числом, иначе вернется "0". Это работает как для целых чисел, так и для float. Использование - это что-то вроде:
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)) }'
немного сложно найти, но его можно использовать в функции, которая возвращает true или false, как [
, grep -q
и т. Д.
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
[[ $VAR = *[[:digit:]]* ]]
возвращает истину , если переменная содержит число, только если это не является целым числом.
[[ "z3*&" = *[[:digit:]]* ]] && echo "numeric"
печатает numeric
. Протестировано в bash версии 3.2.25(1)-release
.
Старый вопрос, но я просто хотел найти решение. Это не требует каких-либо странных трюков оболочки или полагаться на то, что не было навсегда.
if [ -n "$(printf '%s\n' "$var" | sed 's/[0-9]//g')" ]; then
echo 'is not numeric'
else
echo 'is numeric'
fi
В принципе, он просто удаляет все цифры из ввода, и если вы остаетесь с строкой, отличной от нулевой длины, то это не число.
var
.
$'0\n\n\n1\n\n\n2\n\n\n3\n'
.
Не могу комментировать, поэтому я добавлю свой собственный ответ, который является расширением ответа glenn jackman с использованием соответствия шаблону 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)
). Мои модульные тесты проверяют только значения, которые являются либо целыми, либо float, но не являются некорректным вводом.
Я бы попробовал это:
printf "%g" "$var" &> /dev/null
if [[ $? == 0 ]] ; then
echo "$var is a number."
else
echo "$var is not a number."
fi
Примечание: это распознает nan и inf как число.
%f
, вероятно, лучше в любом случае)
if
? Это то, что if
делает ... if printf "%g" "$var" &> /dev/null; then ...
[[ $1 =~ ^-?[0-9]+$ ]] && echo "number"
Не забудьте -
включить отрицательные числа!
=~
существовал по крайней мере еще в bash 3.0.
Ясный ответ уже дал @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] могут быть два знака +/-. Я изучил еще несколько правил работы Aulu и протестировал их против плохих строк, таких как '' '-' '-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
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
Я использую 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
не равно нулю.
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,
Как я должен был вмешаться в это в последнее время и, как и appart с karttu с unit test больше всего. Я пересмотрел код и добавил некоторые другие решения, попробуйте сами, чтобы увидеть результаты:
#!/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
So isNumber() включает тире, запятые и экспоненциальные обозначения и, следовательно, возвращает TRUE для целых чисел и floats, где, с другой стороны isFloat() возвращает FALSE для целочисленных значений, а isInteger() также возвращает FALSE в поплавках. Для вашего удобства все как один вкладыш:
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; }
function
как оно не делает ничего полезного. Кроме того, я не уверен насчет полезности возвращаемых значений. Если не указано иное, функции будут возвращать состояние выхода последней команды, поэтому вам не нужно ничего return
самостоятельно.
return
значения сбивают с толку и делают его менее читабельным. Использование function
ключевых слов или нет - это больше вопрос личного вкуса, по крайней мере, я удалил их из одних строк, чтобы сэкономить место. Спасибо.
Самый простой способ - проверить, содержит ли он символы, отличные от цифр. Вы заменяете все цифровые символы ничем и проверяете длину. Если длина не равна числу.
if [[ ! -n ${input//[0-9]/} ]]; then
echo "Input Is A Number"
fi
Это может быть достигнуто с помощью 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
и |
-q
его в 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]+$'
для чисел с плавающей запятой или двойных чисел.
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.
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]+$'
.
Сделал то же самое здесь с регулярным выражением, которое проверяет всю часть и десятичную часть, разделенные точкой.
re="^[0-9]*[.]{0,1}[0-9]*$"
if [[ $1 =~ $re ]]
then
echo "is numeric"
else
echo "Naahh, not numeric"
fi
.
Следуйте за David W answer от октября '13, если использовать expr
, это может быть лучше
test_var=`expr $am_i_numeric \* 0` >/dev/null 2>&1
if [ "$test_var" = "" ]
then
......
Если числовое значение, умноженное на 1, дает одно и то же значение (включая отрицательные числа). В противном случае вы получите null
, который вы можете проверить для
expr
- зверь, которого трудно приручить. Я не тестировал это решение, но я бы не использовал expr
в пользу современных встроенных оболочек, если только совместимость с устаревшими оболочками начала 1980-х не является важным требованием.
printf '%b' "-123\nABC" | tr '[:space:]' '_' | grep -q '^-\?[[:digit:]]\+$' && echo "Integer." || echo "NOT integer."
Удалите -\?
в шаблоне соответствия grep, если вы не принимаете отрицательное целое число.
Мне нравится ответ Альберто Заккагни.
if [ "$var" -eq "$var" ] 2>/dev/null; then
Важные предпосылки: - не было порожних подоболочек - не активированы парсеры RE - большинство приложений оболочки не используют реальные числа
Но если $var
является сложным (например, ассоциативный доступ к массиву), и если число будет неотрицательным целым числом (большинство случаев использования), то это, пожалуй, более эффективно?
if [ "$var" -ge 0 ] 2> /dev/null; then ..
Я использую 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; }
Вы также можете использовать "let":
[ ~]$ var=1
[ ~]$ let $var && echo "It a number" || echo "It not a number"
It\ a number
[ ~]$ var=01
[ ~]$ let $var && echo "It a number" || echo "It not a number"
It\ a number
[ ~]$ var=toto
[ ~]$ let $var && echo "It a number" || echo "It not a number"
It\ not a number
[ ~]$
Но я предпочитаю использовать оператор "= ~" Bash 3+, как некоторые ответы в этом потоке.
Чтобы уловить отрицательные числа:
if [[ $1 == ?(-)+([0-9.]) ]]
then
echo number
else
echo not a number
fi
1.2.3.4.5.6.7.8
или -........
для проверки
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
Я нашел довольно короткую версию:
function isnum()
{
return `echo "$1" | awk -F"\n" '{print ($0 != $0+0)}'`
}
"0"
?
Быстрая и грязная: я знаю, что это не самый элегантный способ, но я обычно добавлял к нему нуль и тестировал результат. так:
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
}
ПРИМЕЧАНИЕ. Думаю, я никогда не думал проверять наличие поплавков или смешанных типов, которые сделают всю бомбу script... в моем случае я не хотел, чтобы это продвигалось дальше. Я собираюсь поиграть с решением mrucci и регулярным выражением Duffy - они кажутся наиболее надежными в рамках bash...
1+1
, но отклоняет некоторые натуральные числа с ведущими 0
с (потому что 08
- недопустимая восьмеричная константа).
0
не является числом, и это подвергается произвольному внедрению кода, попробуйте это: isInteger 'a[$(ls)]'
. По электронной почте Ой.
Я попробовал рецепт ультрасовременного клинка, поскольку он казался мне самым практичным и не мог заставить его работать. В конце концов я разработал другой способ, хотя, основываясь на других в замещении параметров, на этот раз с заменой регулярных выражений:
[[ "${var//*([[:digit:]])}" ]]; && echo "$var is not numeric" || echo "$var is numeric"
Он удаляет каждый символ: digit: class в $var и проверяет, осталось ли мы с пустой строкой, что означает, что оригинал был только числом.
Что мне нравится в этом, так это его небольшая занимательность и гибкость. В этой форме он работает только для целых чисел без разделителей, основанных на базе 10, хотя, конечно, вы можете использовать сопоставление шаблонов в соответствии с другими потребностями.
Я использую следующее (для целых чисел):
## ##### 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
-n
и т. Д. (Из-за echo
), и вы принимаете переменные с завершающими символами новой строки (из-за $(...)
). И, кстати, print
не является допустимой командой оболочки.
Если у вас установлен 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
если аргумент -n
является числомВы можете захотеть обернуть это в функцию, здесь лучшая версия, которая тоже может читать числа с плавающей точкой.
is_number() { perl -se 'exit($n !~ /^\d+(\.\d+)?$/)' -- -n="$1"; }
Числа могут быть рассчитаны, поэтому запустите номера через калькулятор.
var=81
if (( $(echo "$var == $var" | bc -l 2>/dev/null) )); then
echo "It a number"
else
echo "not a number"
fi
Этот подход обрабатывает целые числа, поплавки, отрицательные числа и терпит неудачу во всем остальном, включая незаявленные и пустые переменные.
Стек выскочил из сообщения, спросил меня, действительно ли я хочу ответить после 30+ ответов? Но конечно!!! Используйте bash новые функции, и вот оно: (после комментария я внес изменения)
function isInt() {([[$ 1 -eq $(($ 1 + 0))]] 2 > /dev/null && & && & [[$ 1!= '']] && & эхо 1) || echo ''}
function isInt() {
([[ $1 =~ ^[-+0-9]+$ ]] && [[ $1 -eq $(( $1 + 0 )) ]] 2>/dev/null && [[ $1 != '' ]] && echo 1) || echo ''
}
Поддержка:
===============out-of-the-box==================
1. negative integers (true & arithmetic),
2. positive integers (true & arithmetic),
3. with quotation (true & arithmetic),
4. without quotation (true & arithmetic),
5. all of the above with mixed signs(!!!) (true & arithmetic),
6. empty string (false & arithmetic),
7. no value (false & arithmetic),
8. alphanumeric (false & no arithmetic),
9. mixed only signs (false & no arithmetic),
================problematic====================
10. positive/negative floats with 1 decimal (true & NO arithmetic),
11. positive/negative floats with 2 or more decimals (FALSE & NO arithmetic).
True/false - это то, что вы получаете из функции только при использовании в сочетании с подстановкой процесса, например, в [[ $( isInt <arg> ) ]]
, поскольку в bash нет логического типа нет возвращаемого значения функции.
Я использую капитал, когда результат тестового выражения WRONG, тогда как он должен быть обратным!
Посредством "арифметики" я имею в виду, что bash может выполнять математику, как в этом выражении: $x=$(( $y + 34))
.
Я использую "арифметику/без арифметики", когда в математических выражениях аргумент действует так, как ожидается, и "НЕТ арифметики", когда он ошибочно работает по сравнению с ожидаемым.
Как вы видите, только 10 и 11 являются проблематичными!
Perfect!
PS: Обратите внимание, что МОСТ популярный ответ не работает в случае 9!
isInt 'a[$(ls>&3)]' 3>&1
. Вы рады, что я использовал ls
только как команду (которая выполняется дважды). И ваш код также утверждает, что a[$(ls>&3)]
- это число.
unset a; isInt a
Это немного грубо по краям, но немного более дружелюбный к новичкам.
if [ $number -ge 0 ]
then
echo "Continue with code block"
else
echo "We matched 0 or $number is not a number"
fi
Это приведет к ошибке и напечатает "Недопустимый номер:", если число $number не является числом, но оно не выйдет из script. Как ни странно, нет тестовой опции, которую я мог бы найти, чтобы просто проверить целое число. Логика здесь будет соответствовать любому числу, которое больше или равно 0.
[[ ]]
вместо [ ]
, в противном случае произойдет сбой в нецелых строках.
Принятый ответ здесь не работает, я нахожусь на MacOS. Работает следующий код:
if [ $(echo "$number" | grep -c '^[0-9]\+$') = 0 ]; then
echo "it is a number"
else
echo "not a number"
fi
1
а не с 0
в утверждении теста. Другая проблема в том, что если переменная number
содержит символы новой строки: number=$'42\nthis is not a number, right?'
будет подтверждено
/bin/sh
- либо через #!/bin/sh
shebang, либо с помощью скрипта, sh scriptname
с sh scriptname
- вместо bash).
Ниже написан Script и используется для интеграции Script с Nagios, и он работает до сих пор
#!/bin/bash
# Script to test variable is numeric or not
# Shirish Shukla
# Pass arg1 as number
a1=$1
a=$(echo $a1|awk '{if($1 > 0) print $1; else print $1"*-1"}')
b=$(echo "scale=2;$a/$a + 1" | bc -l 2>/dev/null)
if [[ $b > 1 ]]
then
echo "$1 is Numeric"
else
echo "$1 is Non Numeric"
fi
EG:
# sh isnumsks.sh "-22.22"
-22.22 is Numeric
# sh isnumsks.sh "22.22"
22.22 is Numeric
# sh isnumsks.sh "shirish22.22"
shirish22.22 is Non Numeric
echo "$a1"
вам нужны двойные кавычки, в противном случае подстановочные знаки в строке раскрываются, и результат зависит от того, какие файлы находятся в текущем каталоге (попробуйте isnumsks.sh "*"
, затем повторите попытку после создания файла с именем 42
). Вы смотрите только на первое слово, разделенное пробелами, поэтому 42 psych
неправильно классифицируется как числовое. Все виды ввода, которые не являются числовыми, но имеют действительный синтаксис bc
могут испортить это, например, 2012-01-03
.
test && echo "foo" && exit 0 || echo "bar" && exit 1
подходtest && echo "foo" && exit 0 || echo "bar" && exit 1
который вы используете, может иметь некоторые непреднамеренные побочные эффекты - если эхо не удается (возможно, вывод на закрытый FD),exit 0
будет пропущен, а затем код попытаетсяecho "bar"
. Если и при этом произойдет сбой, условие&&
не будет выполнено и даже не выполнитexit 1
! Использование фактических операторовif
вместо&&
/||
менее склонен к неожиданным побочным эффектам.