Я просто не могу понять, как мне убедиться, что аргумент, переданный моему сценарию, является числом или нет.
Все, что я хочу сделать, это что-то вроде этого:
test *isnumber* $1 && VAR=$1 || echo "need a number"
Любая помощь?
Я просто не могу понять, как мне убедиться, что аргумент, переданный моему сценарию, является числом или нет.
Все, что я хочу сделать, это что-то вроде этого:
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]+)?$
^-*[0-9]+([.][0-9]+)?$
, чтобы также проверить отрицательные числа
- person Ben; 24.06.2011
^-?
, а не ^-*
, если вы на самом деле не выполняете работу по правильной обработке нескольких инверсий.
- person Charles Duffy; 27.06.2011
^[0-9]*([.][0-9]+)?$
. Это потребует дополнительной проверки непустой строки жестко ..
- person Legionair; 21.05.2013
if ! [[ -n "$yournumber" && "$yournumber" =~ ^-?[0-9]*([.][0-9]+)?$ ]]; then echo NAN; fi
- person Legionair; 21.05.2013
[[ $yournumber =~ ^[0-9]+$ ]]
.
- person konsolebox; 01.09.2013
=~
изменилась между 3.1 и 3.2, тогда как обработка обратной косой черты в присваиваниях постоянна во всех соответствующих выпусках bash. Таким образом, следуя практике постоянного присвоения переменных регулярных выражений перед сопоставлением с ними с помощью =~
, можно избежать сюрпризов. Я делаю это здесь, чтобы научить хорошим привычкам, даже несмотря на то, что это конкретное регулярное выражение не имеет escape-символов обратной косой черты.
- person Charles Duffy; 01.09.2013
=~
начался с 3.0 и с тех пор имел разные реализации. Что на самом деле наиболее сложно, так это то, что вам все равно придется заключать в кавычки символы в значениях переменных, которые вы намеревались предоставить как буквальные (например, ${VAR//./\\.}
), чтобы они не анализировались как символы регулярного выражения, тогда как с ==
вы можете просто поместить их в ""
, например. +(x)"$V"
. И единственная причина, по которой я мог использовать его поверх доп. шаблоны - это когда я мог использовать BASH_REMATCH
.
- person konsolebox; 01.09.2013
[[ $s =~ $re_start"$literal"$re_end ]]
, например, обрабатывает развернутое содержимое "$literal"
как буквальное, экранирование не требуется. (Я также нахожу [.]
значительно более читаемым и более легким в обращении, чем \.
, но, по общему признанию, это велосипедное шеддинг)
- person Charles Duffy; 01.09.2013
[[ $s =~ $re_start"$literal"$re_end ]]
будет работать так же, как ==
, начиная с версии 3.2, но не в версии 3.0 или 3.1. [[ $s =~ (x) ]]
без необходимости экономить на переменной также будет работать только начиная с 4.0. Расширенные шаблоны нужно активировать только один раз в начале скрипта, так что это не имеет особого значения. Он также совместим со всеми версиями bash, начиная с 2.05b. Ну, эти последние мои комментарии уже касались того, почему кто-то предпочел бы расширенные шаблоны =~
. Информация также может быть полезна другим читателям, возможно, если они заботятся о совместимости.
- person konsolebox; 01.09.2013
/bin/sh
- это POSIX sh (или, в древних системах, оболочка Bourne), а не bash, даже если это символическая ссылка на bash.
- person Charles Duffy; 06.12.2013
if [[ 123 =~ '^[0-9]+$' ]]; then echo good; fi
и ничего не получил. Но re='^[0-9]+$'; if [[ 123 =~ $re ]]; then echo good; fi
сказал good
. Почему? Должен ли я что-то убегать в первой версии?
- person Frozen Flame; 01.08.2014
=~
в кавычки, делает его больше не регулярным выражением, а регулярной строкой (в современных версиях bash, но не в некоторых древних), тогда как версия, которую я дал в этом ответе, работает последовательно в каждом выпуске где =~
вообще поддерживается.
- person Charles Duffy; 01.08.2014
.5
? Вместо этого я бы использовал ^-?([0-9]*[.])?[0-9]+$
.
- person HelloGoodbye; 03.06.2015
if
. Остальное см. В BashFAQ № 31 (mywiki.wooledge.org/BashFAQ/031); помимо того, что там описано, !
инвертирует статус выхода команды (делает правду ложной, а ложь - истинной); это распространенный способ написания не на многих-многих языках.
- person Charles Duffy; 11.10.2015
str="hello world"; re='[[:space:]]'; if [[ $str =~ $re ]]; then echo "matched"; fi
ожидаемое поведение на странице ideone.com/K7kM6M.
- person Charles Duffy; 21.07.2019
eval
или какой-либо другой этап предварительного выполнения. Можете ли вы придумать пример, который не работает без кавычек, и опубликовать ссылку на его выполнение на ideone.com?
- person Charles Duffy; 21.07.2019
read
не работает для последней строки, введенной в поле stdin (что можно исправить, поместив пустую строку в конец поля stdin). Однако, кроме этого, у меня исторически не было проблем.
- person Charles Duffy; 22.07.2019
.3
или заканчивается точкой типа 3.
, это НЕ будет работать. Я хотел бы предложить использовать ^[+-]?([0-9]*[.])?([0-9]+)?$
, однако сначала нужно исключить три особых случая: .
, +.
, -.
.
- person Xiang; 12.09.2019
if [[ ! $yournumber =~ $re ]]
?
- person Marco Dufal; 02.07.2020
!
не находится в квадратных скобках в вашем фрагменте кода.
- person Marco Dufal; 02.07.2020
[[ ! $foo && $bar ]]
; читателю необходимо подумать, применяется ли !
только к $foo
или к результату операции И обоих; поместите его снаружи, и с первого взгляда станет очевидным, что отрицание применимо ко всему тесту, а не только к одной его ветви.
- person Charles Duffy; 02.07.2020
^[1-9][0-9]*$
- person Jesse Chisholm; 25.07.2020
return
вместо exit 1
, который также завершает сеанс ssh
- person alper; 28.05.2021
return
.
- person Charles Duffy; 28.05.2021
Без башизмов (работает даже в Системе В ш),
case $string in
''|*[!0-9]*) echo bad ;;
*) echo good ;;
esac
Это отклоняет пустые строки и строки, содержащие не цифры, принимая все остальное.
Отрицательные числа или числа с плавающей запятой требуют дополнительной работы. Идея состоит в том, чтобы исключить -
/ .
из первого «плохого» шаблона и добавить больше «плохих» шаблонов, содержащих их несоответствующее использование (?*-*
/ *.*.*
)
if test ...
- person tripleee; 04.09.2011
${string#-}
(которая не работает в античных оболочках Bourne, но работает в любой оболочке POSIX), чтобы принимать отрицательные целые числа.
- person Gilles 'SO- stop being evil'; 03.01.2012
'.' | *.*.*
к запрещенным шаблонам и добавьте точку к разрешенным символам. Точно так же вы можете разрешить необязательный знак раньше, хотя тогда я бы предпочел case ${string#[-+]}
просто игнорировать знак.
- person tripleee; 07.06.2014
case "$string" in
вместо case $string in
?
- person Dor; 06.10.2016
Следующее решение также можно использовать в базовых оболочках, таких как Bourne, без необходимости использования регулярных выражений. По сути, любые операции оценки числовых значений с использованием нечисловых значений приведут к ошибке, которая неявно будет считаться ложной в оболочке:
"$var" -eq "$var"
as in:
#!/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 ]]
оценивается как истина (оба аргумента преобразуются в ноль)
- person Tgr; 28.08.2012
bash
(который был запрошен) и в большинстве других оболочек, но, к сожалению, не в ksh
. Если вы хотите быть портативным, используйте раствор jilles.
- person Adrian Frühwirth; 04.05.2013
if ! [ $# -eq 1 -o "$1" -eq "$1" ] 2>/dev/null; then
- person haridsv; 02.08.2013
[
встроенных в которых будет оценивать аргументы как арифметические. Это верно как для ksh93, так и для mksh. Кроме того, поскольку оба этих массива поддерживают массивы, существует простая возможность для внедрения кода. Вместо этого используйте сопоставление с образцом.
- person ormaaj; 08.10.2014
[[ ]]
, но не для [ ]
. Тем не менее, это поведение не указано ни в стандарте POSIX для test
, ни в собственной документации bash; будущие версии bash могут изменять поведение в соответствии с ksh без нарушения каких-либо задокументированных поведенческих обещаний, поэтому надежда на сохранение текущего поведения не гарантирует безопасность.
- person Charles Duffy; 26.03.2016
man test
показывает, что -eq
- для целых чисел, а =
- для строк. страница руководства подразумевает, но явно не говорит, что -eq
не сможет выполнить сравнение строк.
- person JDS; 02.09.2016
! [ "$var" -eq "$var" ]
. Причина: -ne
возвращает ненулевое значение для нецелочисленных аргументов.
- person Tom Hale; 04.09.2018
$var
не равно нулю. Я предлагаю отредактировать: [ -n "$var" ] && [ "$var" -eq "$var" ] 2>/dev/null
- person Tom Hale; 04.09.2018
Никто не предлагал расширенное сопоставление с образцом в bash:
[[ $1 == ?(-)+([0-9]) ]] && echo "$1 is an integer"
или используя новый стиль POSIX:
[[ $1 == ?(-)+([:digit:]) ]] && echo "$1 is an integer"
shopt -s extglob
из вашего сообщения (за которое я проголосовал, это один из моих любимых ответов здесь), поскольку в Условные конструкции, вы можете прочитать: Когда используются операторы ==
и !=
, строка справа от оператора считается шаблоном и сопоставляется в соответствии с правилами описано ниже в сопоставлении с шаблоном, как если бы extglob
была включена опция оболочки. Надеюсь, вы не против!
- person gniourf_gniourf; 13.02.2015
3.2.25(1)-release
bash: -bash: syntax error in conditional expression: unexpected token
('-bash: синтаксическая ошибка рядом с `? (-'. В этом выпуске функция, отмеченная @gniourf_gniourf, не работает.
- person Jdamian; 08.09.2016
[[ x3x = *[[:digit:]]* ]]
, даже с одним =
оператор. В справочных страницах 3.2 bash строка as if the extglob shell option were enabled
не найдена.
- person Jdamian; 08.09.2016
?(-)
, который необязательно соответствует начальному дефису, поэтому вы просто сопоставляете цифры с +([0-9])
- person glenn jackman; 15.11.2017
bash 5.0.11
, но разве не должно быть "$1"
вместо $1
? или не имеет значения в этом случае?
- person downtheroad; 14.01.2020
[[...]]
не подлежат разделению на слова или расширению глобуса.
- person glenn jackman; 14.01.2020
[[...]]
в руководстве ( или help [[
в приглашении bash): только правая часть ==
является шаблоном.
- person glenn jackman; 08.12.2020
Это проверяет, является ли число неотрицательным целым числом, независимо от оболочки (то есть без bashisms) и использует только встроенные функции оболочки:
НЕПРАВИЛЬНО.
Поскольку этот первый ответ (ниже) допускает целые числа с символами в них, если первые не являются первыми в переменной.
[ -z "${num##[0-9]*}" ] && echo "is a number" || echo "is not a number";
ПРАВИЛЬНО.
Как jilles прокомментирован и предложен в его ответ, это правильный способ сделать это с помощью шаблонов оболочки.
[ ! -z "${num##*[!0-9]*}" ] && echo "is a number" || echo "is not a number";
*[!0-9]*
- это шаблон, который соответствует всем строкам с хотя бы одним нецифровым символом. ${num##*[!0-9]*}
- это расширение параметра, в котором мы берем содержимое переменной num
и удаляем самую длинную строку, соответствующую шаблону. Если результат расширения параметра не пустой (! [ -z ${...} ]
), то это число, поскольку оно не содержит каких-либо нецифровых символов.
- person mrucci; 26.05.2016
122s
:-(
- person Hastur; 06.04.2018
Я удивлен решениями, непосредственно анализирующими числовые форматы в оболочке. 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 23 && echo "this is a number" || echo "not a number"
- person michael; 19.07.2013
2>/dev/null
, чтобы isnumber "foo"
не загрязнял stderr?
- person gioele; 06.06.2014
isnumber "'a"
вернет истину. Это задокументировано в спецификации POSIX, где вы прочитаете: < i> Если ведущий символ - это одинарная или двойная кавычка, значение должно быть числовым значением в базовом кодовом наборе символа, следующего за одинарной или двойной кавычкой.
- person gniourf_gniourf; 13.02.2015
:D
.
- person gniourf_gniourf; 13.02.2015
isinteger() { [[ $1 ]] && printf '%d' "$1" >/dev/null 2>&1; }
не удастся, например, isinteger 09
: это из-за глупого начального 0
. Теперь вы можете возразить, что 09
не следует проверять ... как бы то ни было, isnumber "'a"
уже является хорошим доказательством того, что вся эта конструкция нарушена.
- person gniourf_gniourf; 13.02.2015
sed "s/^0*//; s/'/^/"
- person pixelbeat; 15.02.2015
isnumber
(функция isinteger
, которую я дал, - это просто (неудачная) попытка обобщения вашего метода). Забавно, но теперь 0
- это не число. Ваша функция теперь порождает 4 подоболочки, использует внешнюю команду, не работает. И вы утверждаете, что оболочка - это просто DSL для управления файлами и процессами? вам нужно изучить лучшие методы работы с оболочкой, и когда вы будете более осведомлены, вы увидите, что единственный разумный способ решить эту проблему - это действительно проанализировать строку.
- person gniourf_gniourf; 15.02.2015
printf
. Например, ваша функция проверяет 42\n\n\n\n\n\n\n\n\n\n\n\n\n
, %s42%s
или %d9
- person gniourf_gniourf; 15.02.2015
$'1\n\n\n'
; это потому, что $(...)
обрезает завершающие символы новой строки. Что бы ни. Вы находитесь в точке, где вы критикуете методы, которые явно анализируют строку (и поэтому мы ожидаем, что ваш метод будет действительно лучше): ваш метод порождает 3 подоболочки, даже не на 100% безопасен (в отношении завершающих символов новой строки), каким-то образом анализирует строка с sed
намного менее эффективна, чем методы, которые непосредственно анализируют строку. Молодец.
- person gniourf_gniourf; 15.02.2015
s/'/^/
. Не могли бы вы уточнить это? Я не понимаю, как замена '
на ^
будет иметь какой-либо смысл (это то, что делает sed
, когда ^
один) при рассмотрении десятичного входного числа.
- person Atralb; 05.11.2020
'blah
как число, поэтому измените его так, чтобы printf отклонил
- person pixelbeat; 06.11.2020
Я смотрел ответы и ... понял, что никто не думал о числах 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
Чтобы сопоставить ТОЛЬКО целые числа, используйте это:
# change check line to:
check=`echo "$1" | grep -E ^\-?[0-9]+$`
(2-й) Полный текст этого ответа: 27 июня 2021 г.
Есть несколько сильно различающихся методов в отношении разных видов тестов.
Я рассмотрел наиболее подходящие методы и построил это сравнение.
is_uint()
Эти функции реализуют код для оценки того, является ли выражение целым числом без знака, т. Е. Полностью ли оно состоит из цифр.
Использование расширения параметров
(Это был мой подход до всего этого!)
isuint_Parm() { [ "$1" ] && [ -z "${1//[0-9]}" ] ;}
Использование вилки для grep
isuint_Grep() { grep -qE '^[0-9]+$' <<<"$1"; }
Я тестирую этот метод только один раз, потому что он очень медленный. Это просто для того, чтобы показать, чего нельзя делать.
Использование целочисленных возможностей bash < / strong>
isuint_Bash() { (( 10#$1 >= 0 )) 2>/dev/null ;}
Использование case
isuint_Case() { case $1 in ''|*[!0-9]*) return 1;;esac;}
Использование регулярного выражения bash
isuint_Regx() { [[ $1 =~ ^[0-9]+$ ]] ;}
is_int()
Эти функции реализуют код для оценки того, является ли выражение целым числом со знаком, т. Е. Как указано выше, но разрешая необязательный знак перед числом.
Использование расширения параметров
isint_Parm() { local chk=${1#[+-]}; [ "$chk" ] && [ -z "${chk//[0-9]}" ] ;}
Использование целочисленных возможностей bash < / strong>
isint_Bash() { (( 10#$1 )) 2>/dev/null ;}
Использование case
isint_Case() { case ${1#[-+]} in ''|*[!0-9]*) return 1;;esac;}
Использование регулярного выражения bash
isint_Regx() { [[ $1 =~ ^[+-]?[0-9]+$ ]] ;}
is_num()
Эти функции реализуют код для оценки того, является ли выражение числом с плавающей запятой, т. Е. Как указано выше, но разрешая необязательную десятичную точку и дополнительные цифры после нее. Это не пытается охватить числовые выражения в экспоненциальной нотации (например, 1.0234E-12).
Использование расширения параметров
isnum_Parm() { local ck=${1#[+-]};ck=${ck/.};[ "$ck" ]&&[ -z "${ck//[0-9]}" ];}
Использование регулярного выражения bash
isnum_Regx() { [[ $1 =~ ^[+-]?([0-9]+([.][0-9]*)?|\.[0-9]+)$ ]] ;}
Использование case
isnum_Case() { case ${1#[-+]} in ''|.|*[!0-9.]*|*.*.*) return 1;; esac ;}
(Вы можете скопировать / вставить этот тестовый код после ранее объявленных функций.)
testcases=(
1 42 -3 +42 +3. .9 3.14 +3.141 -31.4 '' . 3-3 3.1.4 3a a3 blah 'Good day!'
);printf '%-12s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s\n' Function \
U{Prm,Grp,Bsh,Cse,Rgx} I{Prm,Bsh,Cse,Rgx} N{Prm,Cse,Rgx}; \
for var in "${testcases[@]}";do
outstr='';
for func in isuint_{Parm,Grep,Bash,Case,Regx} isint_{Parm,Bash,Case,Regx} \
isnum_{Parm,Case,Regx};do
if $func "$var"
then outstr+=' num'
else outstr+=' str'
fi
done
printf '%-11s %s\n' "|$var|" "$outstr"
done
Должен выводить:
Function UPrm UGrp UBsh UCse URgx IPrm IBsh ICse IRgx NPrm NCse NRgx
|1| num num num num num num num num num num num num
|42| num num num num num num num num num num num num
|-3| str str str str str num num num num num num num
|+42| str str num str str num num num num num num num
|+3.| str str str str str str str str str num num num
|.9| str str str str str str str str str num num num
|3.14| str str str str str str str str str num num num
|+3.141| str str str str str str str str str num num num
|-31.4| str str str str str str str str str num num num
|| str str num str str str str str str str str str
|.| str str str str str str str str str str str str
|3-3| str str num str str str str str str str str str
|3.1.4| str str str str str str str str str str str str
|3a| str str str str str str str str str str str str
|a3| str str str str str str str str str str str str
|blah| str str str str str str str str str str str str
|Good day!| str str str str str str str str str str str str
Я надеюсь! (Примечание: uint_bash
кажутся не идеальными!)
Затем я построил эту тестовую функцию:
testFunc() {
local tests=1000 start=${EPOCHREALTIME//.}
for ((;tests--;)) ;do
"$1" "$3"
done
printf -v "$2" %u $((${EPOCHREALTIME//.}-start))
}
percent(){ local p=00$((${1}00000/$2));printf -v "$3" %.2f%% ${p::-3}.${p: -3};}
sortedTests() {
local func NaNTime NumTime ftyp="$1" nTest="$2" tTest="$3" min i pct line
local -a order=()
shift 3
for func ;do
testFunc "${ftyp}_$func" NaNTime "$tTest"
testFunc "${ftyp}_$func" NumTime "$nTest"
order[NaNTime+NumTime]=${ftyp}_$func\ $NumTime\ $NaNTime
done
printf '%-12s %11s %11s %14s\n' Function Number NaN Total
min="${!order[*]}" min=${min%% *}
for i in "${!order[@]}";do
read -ra line <<<"${order[i]}"
percent "$i" "$min" pct
printf '%-12s %9d\U00B5s %9d\U00B5s %12d\U00B5s %9s\n' \
"${line[@]}" "$i" "$pct"
done
}
Я мог бежать так:
sortedTests isuint "This is not a number." 31415926535897932384 \
Case Grep Parm Bash Regx ;\
sortedTests isint "This is not a number." 31415926535897932384 \
Case Parm Bash Regx ;\
sortedTests isnum "This string is clearly not a number..." \
3.141592653589793238462643383279502884 Case Parm Regx
На моем хосте это показывает:
Function Number NaN Total
isuint_Case 6762µs 8492µs 15254µs 100.00%
isuint_Bash 13478µs 12739µs 26217µs 171.87%
isuint_Parm 11324µs 18807µs 30131µs 197.53%
isuint_Regx 20777µs 27616µs 48393µs 317.25%
isuint_Grep 1516390µs 1491751µs 3008141µs 19720.34%
Function Number NaN Total
isint_Case 8630µs 8042µs 16672µs 100.00%
isint_Bash 14254µs 12272µs 26526µs 159.10%
isint_Parm 16445µs 20491µs 36936µs 221.54%
isint_Regx 23661µs 28287µs 51948µs 311.59%
Function Number NaN Total
isnum_Case 9579µs 10328µs 19907µs 100.00%
isnum_Parm 21115µs 28983µs 50098µs 251.66%
isnum_Regx 35552µs 58453µs 94005µs 472.22%
case
путь явно самый быстрый! Примерно в 3 раза быстрее, чем regex
, и в 2 раза быстрее, чем при использовании расширения параметров.grep
или любых двоичных файлов) следует избегать, когда они не нужны.case
стал моим любимым выбором:
is_uint() { case $1 in '' | *[!0-9]* ) return 1;; esac ;}
is_int() { case ${1#[-+]} in '' | *[!0-9]* ) return 1;; esac ;}
is_unum() { case $1 in '' | . | *[!0-9.]* | *.*.* ) return 1;; esac ;}
is_num() { case ${1#[-+]} in '' | . | *[!0-9.]* | *.*.* ) return 1;; esac ;}
Для этого я написал небольшой тестовый сценарий, основанный на предыдущих тестах, с:
for shell in bash dash 'busybox sh' ksh zsh "$@";do
printf "%-12s " "${shell%% *}"
$shell < <(testScript) 2>&1 | xargs
done
Это показывает:
bash Success
dash Success
busybox Success
ksh Success
zsh Success
Насколько мне известно, другое решение на основе bash, например регулярное выражение и целое число bash не будет работать во многих других оболочках, а вилки требуют больших ресурсов, я бы предпочитайте способ case
(непосредственно перед расширением параметров, которое также в большинстве случаев совместимо).
set --
может использоваться для установки позиционных параметров
- person fire; 24.07.2020
case
ответ в сравнение? Он получил мой голос как за простоту, так и за элегантность. В моих тестах это значительно быстрее, чем обе ваши альтернативы. В IdeOne это менее очевидно, но все же быстрее: ideone.com/AVvMOU
- person tripleee; 24.06.2021
casenum
не работают с плавающими числами! И его тест не использует его $fun
переменную !! Но я согласен, я мог бы обратить внимание на этот способ работы!
- person F. Hauri; 24.06.2021
case
(sic) теперь явно быстрее и на IdeOne. (Я должен был проверить ...) Хотя, вероятно, лучший тест не только проверял бы успех.
- person tripleee; 24.06.2021
isuint_Bash
немного быстрее, чем case
в NaN
тесте. Если вы находитесь в замкнутом цикле, где учитывается каждый цикл, и ожидаете, что вводимые данные в основном недействительны, это может изменить сравнение в пользу версии с расширением параметров. Но только для случая uint
. Возможно, разница настолько мала, что в любом случае находится в пределах погрешности измерения.
- person tripleee; 28.06.2021
+Numberr
, я не буду пытаться там это объяснять;)
- person F. Hauri; 28.06.2021
csh
здесь совершенно неверна, это все равно, что передать код Фортрана Python и удивиться, что он не работает. Оболочки семейства C - это совершенно отдельный язык с другим синтаксисом и функциями, и они несовместимы с оболочками семейства Bourne (за исключением тривиальных сценариев, которые запускают только внешние команды, так же, как вы ожидаете, что пакетный сценарий Windows будет работать в Unix. если действительно просто). Так или иначе, здравомыслящие люди отказались от csh
и друзей около 30 лет назад; просто позволь ему умереть.
- person tripleee; 29.06.2021
csh
удален из сообщения и скрипта.
- person F. Hauri; 29.06.2021
Просто продолжение @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
и т. Д.
- person tripleee; 02.08.2017
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
man -P 'less +/parameter\/' bash
часть. Узнавать что-то новое каждый день. :)
- person David; 11.04.2019
\-
в регулярное выражение, чтобы решить эту проблему. Используйте [0-9\-\.\+]
для учета чисел с плавающей запятой и чисел со знаком.
- person user2683246; 09.05.2019
echo $i | python -c $'import sys\ntry:\n float(sys.stdin.read().rstrip())\nexcept:\n sys.exit(1)' && echo yes || echo no
- person user2683246; 09.05.2019
Для моей проблемы мне нужно было только убедиться, что пользователь случайно не введет какой-либо текст, поэтому я старался сделать его простым и читабельным.
isNumber() {
(( $1 )) 2>/dev/null
}
Согласно странице руководства, это в значительной степени то, что я хочу
Если значение выражения не равно нулю, статус возврата равен 0.
Чтобы предотвратить неприятные сообщения об ошибках для строк, которые «могут быть числами», я игнорирую вывод ошибок
$ (( 2s ))
bash: ((: 2s: value too great for base (error token is "2s")
foo=1;set -- foo;(( $1 )) 2>/dev/null && echo "'$1' is a number"
- person F. Hauri; 25.06.2021
Этого можно добиться, используя grep
, чтобы увидеть, соответствует ли рассматриваемая переменная расширенному регулярному выражению.
1120
:yournumber=1120
if echo "$yournumber" | grep -qE '^[0-9]+$'; then
echo "Valid number."
else
echo "Error: not a number."
fi
Выход: Valid number.
1120a
:yournumber=1120a
if 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]+$'
для чисел с плавающей или двойной точностью.
1120.01
:yournumber=1120.01
if 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.01
if 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]+$'
.
[-]
вместо \-
и [.]
вместо \.
немного более многословно, но это означает, что ваши строки не должны измените, если они используются в контексте, где используются обратные косые черты).
- person Charles Duffy; 16.03.2020
if [[ $yournumber =~ ^[0-9]+([.][0-9]+)?$ ]] ; then
в старой системе на основе Ubuntu 14.04, но каким-то образом он перестал работать после обновления до Ubuntu 20.04, ваше первое решение для Test Integer делает то же самое в 20.04. Я не могу сказать, связано ли это с обновлением, или, может быть, мой сценарий был неправильным в первую очередь и - почему-то - все же работал в старой системе. Большое тебе спасибо.
- person Geppettvs D'Constanzo; 07.07.2020
#!/bin/sh
? Если это так, он должен работать в современной Ubuntu, если вы используете #!/bin/bash
shebang, и избегайте запуска скриптов с sh scriptname
(который игнорирует shebang и заставляет использовать sh
вместо bash
).
- person Charles Duffy; 11.08.2020
Старый вопрос, но я просто хотел остановиться на своем решении. Этот не требует каких-либо странных уловок с оболочкой и не полагается на то, чего не было вечно.
if [ -n "$(printf '%s\n' "$var" | sed 's/[0-9]//g')" ]; then
echo 'is not numeric'
else
echo 'is numeric'
fi
По сути, он просто удаляет все цифры из ввода, и если у вас осталась строка ненулевой длины, то это не было числом.
var
.
- person gniourf_gniourf; 14.02.2015
$'0\n\n\n1\n\n\n2\n\n\n3\n'
.
- person gniourf_gniourf; 14.02.2015
Я бы попробовал это:
printf "%g" "$var" &> /dev/null
if [[ $? == 0 ]] ; then
echo "$var is a number."
else
echo "$var is not a number."
fi
Примечание: это распознает nan и inf как числа.
%f
, вероятно, в любом случае лучше)
- person michael; 19.07.2013
if
? Вот что делает if
... if printf "%g" "$var" &> /dev/null; then ...
- person Camilo Martin; 26.06.2014
'a
.
- person gniourf_gniourf; 14.02.2015
Пока не могу комментировать, поэтому я добавлю свой собственный ответ, который является расширением ответа Гленна Джекмана с использованием сопоставления с шаблоном 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)
). Мои модульные тесты проверяют только значения, которые являются целыми или плавающими, но не содержат недопустимые входные данные.
Четкий ответ уже дал @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 или иначе будут экспортировать плавающие числа таким образом), полезным дополнением к этой строке будет следующее:
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
[[ $1 =~ ^-?[0-9]+$ ]] && echo "number"
Не забывайте -
включать отрицательные числа!
=~
существовал как минимум еще в bash 3.0.
- person Gilles 'SO- stop being evil'; 23.08.2014
Я использую 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,
- person gniourf_gniourf; 14.02.2015
expr
. Если вы ограничены меньшей оболочкой Борна, такой как POSIX sh
, тогда возможно.
- person tripleee; 24.06.2021
Поскольку мне пришлось вмешиваться в это в последнее время, и мне больше всего нравится приложение karttu с модульным тестом. Я отредактировал код и добавил еще несколько решений, попробуйте сами, чтобы увидеть результаты:
#!/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 () включает дефисы, запятые и экспоненциальную нотацию и поэтому возвращает ИСТИНА для целых чисел и чисел с плавающей запятой, тогда как, с другой стороны, isFloat () возвращает ЛОЖЬ для целочисленных значений и 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
делать самостоятельно.
- person Tom Fenech; 09.09.2016
return
сбивают с толку и делают его менее читаемым. Использование function
ключевых слов или нет - это скорее вопрос личного вкуса, по крайней мере, я удалил их из одних вкладышей, чтобы сэкономить место. Спасибо.
- person 3ronco; 09.09.2016
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:]] вернет истину. Здесь небольшая ловушка, 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:]]* ]]
вернет истину, если переменная содержит число, но не если оно является целым числом.
- person glenn jackman; 26.10.2012
[[ "z3*&" = *[[:digit:]]* ]] && echo "numeric"
печатает numeric
. Проверено в bash версии 3.2.25(1)-release
.
- person Jdamian; 08.09.2016
[[ -n $VAR && $VAR != *[^[:digit:]]* ]]
- person eschwartz; 23.10.2018
Я использую 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; }
Самый простой способ - проверить, не содержит ли он нецифровых символов. Вы заменяете все цифровые символы ничем и проверяете длину. Если есть длина, это не число.
if [[ ! -n ${input//[0-9]/} ]]; then
echo "Input Is A Number"
fi
Мне нравится ответ Альберто Закканьи.
if [ "$var" -eq "$var" ] 2>/dev/null; then
Важные предварительные условия: - не созданы подоболочки - не задействованы парсеры RE - большинство приложений оболочки не используют действительные числа
Но если $var
является сложным (например, доступ к ассоциативному массиву), и если число будет неотрицательным целым числом (в большинстве случаев использования), то это, возможно, более эффективно?
if [ "$var" -ge 0 ] 2> /dev/null; then ..
Чтобы поймать отрицательные числа:
if [[ $1 == ?(-)+([0-9.]) ]]
then
echo number
else
echo not a number
fi
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
- person Badr Elmers; 13.05.2019
Вы также можете использовать "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+ "= ~", как некоторые ответы в этой теме.
printf '%b' "-123\nABC" | tr '[:space:]' '_' | grep -q '^-\?[[:digit:]]\+$' && echo "Integer." || echo "NOT integer."
Удалите -\?
в шаблоне соответствия grep, если вы не принимаете отрицательное целое число.
То же самое и здесь с регулярным выражением, которое проверяет всю часть и часть десятичных знаков, разделенных точкой.
re="^[0-9]*[.]{0,1}[0-9]*$"
if [[ $1 =~ $re ]]
then
echo "is numeric"
else
echo "Naahh, not numeric"
fi
.
- person gniourf_gniourf; 07.05.2018
a=''
и строку, содержащую только точку a='.'
, поэтому ваш код немного не работает ...
- person gniourf_gniourf; 09.05.2018
Я использую следующее (для целых чисел):
## ##### 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
не является допустимой командой оболочки.
- person gniourf_gniourf; 14.02.2015
Я попробовал рецепт ультрапильного полотна, так как он мне показался наиболее практичным, и не смог заставить его работать. В конце концов, я разработал другой способ, основанный, как и другие, на подстановке параметров, на этот раз с заменой регулярного выражения:
[[ "${var//*([[:digit:]])}" ]]; && echo "$var is not numeric" || echo "$var is numeric"
Он удаляет каждый символ: digit: class в $ var и проверяет, осталась ли у нас пустая строка, что означает, что исходный текст был только числами.
Что мне нравится в этом, так это его компактность и гибкость. В этой форме он работает только с целыми числами без разделителей с основанием 10, хотя, конечно, вы можете использовать сопоставление с образцом для удовлетворения других потребностей.
sed
- это POSIX, а ваше решение - bash
. Оба имеют свое применение
- person v010dya; 11.04.2020
Быстрый и грязный: я знаю, что это не самый элегантный способ, но обычно я просто добавлял к нему ноль и проверял результат. вот так:
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 и регулярным выражением Duffy - они кажутся наиболее надежными в рамках bash ...
1+1
, но отклоняет некоторые положительные целые числа с ведущими 0
(потому что 08
является недопустимой восьмеричной константой).
- person Gilles 'SO- stop being evil'; 03.01.2012
0
не является числом, и он может быть введен произвольным кодом, попробуйте: isInteger 'a[$(ls)]'
. Ой.
- person gniourf_gniourf; 14.02.2015
$((...))
не заключено в кавычки, числовое IFS=123
изменит его.
- person ImHere; 20.11.2018
Нашел довольно короткую версию:
function isnum()
{
return `echo "$1" | awk -F"\n" '{print ($0 != $0+0)}'`
}
"0"
?
- person naught101; 30.05.2012
переменная для проверки
number=12345
or number=-23234
or number=23.167
or number=-345.234
проверьте числовой или нечисловой
echo $number | grep -E '^-?[0-9]*\.?[0-9]*$' > /dev/null
принять решение о дальнейших действиях на основании статуса выхода из вышеуказанного
if [ $? -eq 0 ]; then echo "Numeric"; else echo "Non-Numeric"; fi
Продолжая ответ Дэвида В. от октября 2013 г., при использовании expr
это может быть лучше
test_var=`expr $am_i_numeric \* 0` >/dev/null 2>&1
if [ "$test_var" = "" ]
then
......
Если числовой, умноженный на 1, вы получите то же значение (включая отрицательные числа). В противном случае вы получите null
, который можно проверить на
expr
- зверь, которого трудно приручить. Я не тестировал это решение, но я бы не стал expr
в пользу современных встроенных команд оболочки, если только совместимость с устаревшими оболочками начала 1980-х годов не является важным требованием.
- person tripleee; 02.08.2017
Синтаксис почти такой, как вы хотите. Просто нужна функция isnumber
:
#!/usr/bin/bash
isnumber(){
num=$1
if [ -z "${num##*[!0-9]*}" ];
then return 1
else
return 0
fi
}
$(isnumber $1) && VAR=$1 || echo "need a number";
echo "VAR is $VAR"
тестовое задание:
$ ./isnumtest 10
VAR is 10
$ ./isnumtest abc10
need a number
VAR is
Простое для понимания и совместимое решение с командой test
:
test $myVariable -eq 0 2>/dev/null
if [ $? -le 1 ]; then echo 'ok'; else echo 'KO'; fi
Если myVariable = 0, код возврата - 0
Если myVariable ›0, код возврата - 1
Если myVariable не целое число, код возврата - 2
Принятый ответ не работал у меня во всех случаях BASH 4+, поэтому:
# -- is var an integer? --
# trim leading/trailing whitespace, then check for digits return 0 or 1
# Globals: None
# Arguments: string
# Returns: boolean
# --
is_int() {
str="$(echo -e "${1}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
case ${str} in ''|*[!0-9]*) return 1 ;; esac
return 0
}
Как это использовать ?
Действителен (вернет 0 = истина):
is_int "100" && echo "return 0" || echo "return 1"
Неверно (вернет 1 = ложь):
is_int "100abc" && echo "returned 0" || echo "returned 1"
is_int "" && echo "returned 0" || echo "returned 1"
is_int "100 100" && echo "returned 0" || echo "returned 1"
is_int " " && echo "returned 0" || echo "returned 1"
is_int $NOT_SET_VAR && echo "returned 0" || echo "returned 1"
is_int "3.14" && echo "returned 0" || echo "returned 1"
Выход:
returned 0
returned 1
returned 1
returned 1
returned 1
returned 1
returned 1
обратите внимание, в Bash 1 = false, 0 = true. Я просто распечатываю его там, где более вероятно что-то вроде этого:
if is_int ${total} ; then
# perform some action
fi
echo -e
будет вводить ошибки переносимости - в некоторых оболочках он выводит -e
на выходе (и те оболочки, где это не делает это, нарушают букву Спецификация POSIX для echo
; с правильным набором флагов времени выполнения, установленным, чтобы сделать его более строгим совместим, чем обычно, это означает, что bash тоже может печатать -e
на выходе при запуске echo -e
).
- person Charles Duffy; 16.08.2019
Принятый ответ здесь не работает, я использую 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?'
будет проверяться.
- person gniourf_gniourf; 15.02.2015
/bin/sh
- либо через #!/bin/sh
shebang, либо через сценарий, начинающийся с sh scriptname
, а не bash).
- person Charles Duffy; 24.05.2016
grep -c
в подстановке команд и сравнение результата с 0 - распространенный и чрезвычайно запутанный антипаттерн. См. бесполезное использование grep
и дополнительную страницу логики кренделя.
- person tripleee; 02.08.2017
Стек выскочил, и меня спросили, действительно ли я хочу ответить после 30+ ответов? Но конечно!!! Используйте новые функции bash, и вот они: (после комментария я внес изменения)
function isInt () {([[$ 1 -eq $ (($ 1 + 0))]] 2> / dev / null && [[$ 1! = '']] && echo 1) || эхо ''}
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).
Истина / ложь - это то, что вы получаете от функции только при использовании в сочетании с подстановкой процесса, как в [[ $( isInt <arg> ) ]]
, поскольку в bash нет логического типа и return em > значение функции.
Я использую заглавную букву, когда результат тестового выражения НЕПРАВИЛЬНЫЙ, тогда как должно быть наоборот!
Под «арифметикой» я подразумеваю, что bash может выполнять математику, как в этом выражении: $x=$(( $y + 34))
.
Я использую «арифметика / не арифметика», когда в математических выражениях аргумент действует так, как ожидалось, и «НЕ арифметика», когда он ведет себя неправильно по сравнению с ожидаемым.
Как видите, проблемными являются только №10 и №11!
Идеально!
PS: обратите внимание, что САМЫЙ популярный ответ не работает в случае 9!
isInt 'a[$(ls>&3)]' 3>&1
. Вы рады, что я использовал ls
только как команду (которая выполняется дважды). И ваш код также утверждает, что a[$(ls>&3)]
- это число.
- person gniourf_gniourf; 25.09.2016
unset a; isInt a
.
- person gniourf_gniourf; 25.09.2016
Это немного грубовато, но немного более дружелюбно для новичков.
if [ $number -ge 0 ]
then
echo "Continue with code block"
else
echo "We matched 0 or $number is not a number"
fi
Это вызовет ошибку и напечатает «Illegal number:», если $ number не является числом, но он не выйдет из сценария. Как ни странно, я не смог найти тестовой опции, чтобы просто проверить целое число. Логика здесь будет соответствовать любому числу, которое больше или равно 0.
[[ ]]
вместо [ ]
, в противном случае он не работает с нецелочисленными строками.
- person naught101; 30.05.2012
-ge
больше или равно, поэтому он не должен пропускать 0, но пропускает отрицательные числа. Вышеупомянутое решение также работает лучше, поскольку [[ ]]
всегда будет приводить к номеру для ответа @defim, но отлично работает для [ ]
, поскольку оно генерирует ошибку и оценивает как false.
- person Marcus; 07.12.2019
[ "$number" -eq "$number" 2>/dev/null ] && echo isNumber || echo noNumber
- person defim; 09.12.2019
Ниже приведен сценарий, написанный мной и использованный для интеграции сценария с 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
.
- person Gilles 'SO- stop being evil'; 03.01.2012
test && echo "foo" && exit 0 || echo "bar" && exit 1
, который вы используете, может иметь некоторые непреднамеренные побочные эффекты - если эхо не удается (возможно, вывод на закрытый FD),exit 0
будет пропущен, а затем код будет пытатьсяecho "bar"
. Если это тоже не удается, условие&&
не выполняется, и оно даже не будет выполнятьсяexit 1
! Использование фактических операторовif
вместо _7 _ / _ 8_ менее подвержено неожиданным побочным эффектам. - person Charles Duffy   schedule 24.08.2011[[ $1 =~ "^[0-9]+$" ]] && { echo "number"; exit 0; } || { echo "not a number"; exit 1; }
Фигурные скобки указывают на то, что вещи НЕ должны выполняться в подоболочке (что определенно было бы так, если бы вместо них использовались()
круглые скобки). Предупреждение: Никогда не пропускайте последнюю точку с запятой. В противном случае вы можете заставитьbash
распечатать самые уродливые (и самые бессмысленные) сообщения об ошибках ... - person syntaxerror   schedule 09.06.2015[[ 12345 =~ ^[0-9]+$ ]] && echo OKKK || echo NOOO
- person Treviño   schedule 10.09.2015