Я пытаюсь сделать что-то достаточно распространенное: анализировать вводимые пользователем данные в сценарии оболочки. Если пользователь предоставил действительное целое число, сценарий выполняет одно действие, а если он недопустим, - другое. Проблема в том, что я не нашел простого (и достаточно элегантного) способа сделать это - я не хочу, чтобы ему приходилось разбирать char на char.
Я знаю, что это должно быть легко, но не знаю как. Я мог бы сделать это на десятке языков, но не на БАШЕ!
В своем исследовании я обнаружил следующее:
И там есть ответ, в котором говорится о регулярном выражении, но, насколько я знаю, эта функция доступна в C (среди прочего). Тем не менее, это выглядело как отличный ответ, поэтому я попробовал его с помощью grep, но grep не знал, что с ним делать. Я попробовал -P, что на моем поле означает рассматривать его как регулярное выражение PERL - нада. Dash E (-E) тоже не работал. И -F тоже.
Чтобы быть ясным, я пробую что-то подобное, ищу какой-либо вывод - оттуда я взламываю сценарий, чтобы использовать все, что я получаю. (IOW, я ожидал, что несоответствующий ввод ничего не вернет, а действительная строка будет повторяться.)
snafu=$(echo "$2" | grep -E "/^[-+]?(?:\.[0-9]+|(?:0|[1-9][0-9]*)(?:\.[0-9]*)?)$/")
if [ -z "$snafu" ] ;
then
echo "Not an integer - nothing back from the grep"
else
echo "Integer."
fi
Не могли бы вы проиллюстрировать, как это проще всего сделать?
Честно говоря, это, на мой взгляд, недостаток TEST. У него должен быть такой флаг
if [ -I "string" ] ;
then
echo "String is a valid integer."
else
echo "String is not a valid integer."
fi
источник
[
старая совместимаяtest
;[[
это новая вещь Bash, с большим количеством операций и другими правилами цитирования. Если вы уже решили придерживаться Bash, сделайте[[
это (он намного лучше); если вам нужна переносимость на другие оболочки,[[
полностью избегайте .Ответы:
^
указывает на начало входного шаблона.-
Является буквальным «-»?
означает «0 или 1 из предшествующего (-
)»+
средства «1 или более из предшествующих ([0-9]
)»$
указывает на конец входного шаблонаТаким образом, регулярное выражение соответствует необязательному
-
(в случае отрицательных чисел), за которым следует одна или несколько десятичных цифр.Ссылки :
источник
+
средства «1 или более из предшествующих», и$
указывает конец входного образа. Таким образом, регулярное выражение соответствует необязательному,-
за которым следует одна или несколько десятичных цифр.[A-z]
не только даст вамA-Z
и ,a-z
но и\
,[
,]
,^
,_
, и`
.d[g-i]{2}
может закончиться не только сопоставлением,dig
но иdish
сопоставлением, предложенным этим ответом (гдеsh
орграф считается одним символом, сопоставленным послеh
).Ух ты ... тут столько хороших решений !! Из всех вышеперечисленных решений я согласен с @nortally, что использование
-eq
одного лайнера - самое крутое.Я запускаю GNU bash, версия
4.1.5
(Debian). Я также проверял это на ksh (SunSO 5.10).Вот моя версия проверки,
$1
является ли целое число или нет:Этот подход также учитывает отрицательные числа, которые в некоторых других решениях будут иметь ошибочный отрицательный результат, и он позволит использовать префикс «+» (например, +30), который, очевидно, является целым числом.
Полученные результаты:
Решение, предоставленное Игнасио Васкес-Абрамсом, также было очень аккуратным (если вам нравится регулярное выражение) после того, как оно было объяснено. Однако он не обрабатывает положительные числа с
+
префиксом, но его легко исправить, как показано ниже:источник
Опоздавший на вечеринку здесь. Я очень удивлен, что ни в одном из ответов не упоминается самое простое, быстрое и портативное решение;
case
заявление.Обрезка любого знака перед сравнением кажется некоторой уловкой, но это значительно упрощает выражение для оператора case.
источник
''|*[!0-9]*)
Мне нравится решение, использующее
-eq
тест, потому что оно в основном однострочное.Мое собственное решение заключалось в том, чтобы использовать расширение параметров, чтобы выбросить все цифры и посмотреть, осталось ли что-нибудь. (Я все еще использую 3.0, не использовал
[[
иexpr
раньше, но рад их встретить.)источник
[ -z "${INPUT_STRING//[0-9]}" ]
действительно хорошее решение!-eq
решения есть некоторые проблемы; см. здесь: stackoverflow.com/a/808740/1858225Для переносимости на pre-Bash 3.1 (когда
=~
был представлен тест) используйтеexpr
.expr STRING : REGEX
ищет REGEX, закрепленный в начале STRING, повторяя первую группу (или длину совпадения, если нет) и возвращая успех / неудачу. Это старый синтаксис регулярных выражений, отсюда и его избыток\
.-\?
означает «может быть-
»,[0-9]\+
означает «одну или несколько цифр» и$
означает «конец строки».Bash также поддерживает расширенные глобусы, хотя я не помню, с какой версии и далее.
@(-|)
означает «-
или ничего»,[0-9]
означает «цифру» и*([0-9])
означает «ноль или более цифр».источник
awk
,~
был «регулярное выражение матч» оператора. В Perl (как скопировано из C)~
уже использовалось «битовое дополнение», поэтому они использовали=~
. Позднее это обозначение было скопировано на несколько других языков. (Perl 5.10 и Perl 6 любят~~
больше, но здесь это не влияет.) Я полагаю, вы могли бы рассматривать это как своего рода примерное равенство ...Вот еще один вариант (только с использованием встроенной команды test и ее кода возврата):
источник
$()
сif
. Это работает:if is_int "$input"
. Кроме того, эта$[]
форма устарела.$(())
Вместо этого используйте . Внутри любой знак доллара можно опустить:echo "Integer: $((input))"
фигурные скобки нигде в вашем скрипте не нужны.test
, похоже, не поддерживает это.[[
хотя делает.[[ 16#aa -eq 16#aa ]] && echo integer
печатает «целое число».[[
этот метод возвращает ложные срабатывания; например,[[ f -eq f ]]
успешно. Поэтому он должен использоватьtest
или[
.Вы можете удалить нецифровые цифры и провести сравнение. Вот демонстрационный сценарий:
Вот как выглядит тестовый результат:
источник
${var//string}
и${var#string}
и в разделе под названием «Pattern Matching» для [^ [: цифры:]] `(который также покрытman 7 regex
).match=${match#0*}
вовсе не полосы ведущих нулей, то полосы не более одного нуля. Используя расширение, это может быть достигнуто только сextglob
помощью viamatch=${match##+(0)}
.09
не является целым числом, если вы считаете, что целое число не имеет ведущих нулей. Проверка заключается в том, соответствует ли input (09
) очищенной версии (9
- целому числу), а это не так.Для меня самым простым решением было использовать переменную внутри
(())
выражения, например:Конечно, это решение действительно только в том случае, если нулевое значение не имеет смысла для вашего приложения. В моем случае это оказалось правдой, и это намного проще, чем другие решения.
Как указано в комментариях, это может привести к атаке выполнения кода:
(( ))
операторVAR
выполняет оценку , как указано вArithmetic Evaluation
разделе справочной страницы bash (1) . Следовательно, вы не должны использовать эту технику, когда источник содержимогоVAR
неизвестен (и, конечно, вы не должны использовать ЛЮБУЮ другую форму расширения переменных).источник
if (( var )); then echo "$var is an int."; fi
VAR='a[$(ls)]'; if ((VAR > 0)); then echo "$VAR is a positive integer"; fi
. На данный момент вы рады, что я не ввел какую-то злую команду вместоls
. Поскольку OP упоминает ввод пользователя , я действительно надеюсь, что вы не используете его с вводом пользователя в производственном коде!agent007
или с помощью sed:
источник
test -z "${string//[0-9]/}" && echo "integer" || echo "no integer"
... хотя это в основном дублирует ответ Денниса Уильямсонаif [[ -n "$(printf "%s" "${2}" | sed s/[0-9]//g)" ]]; then
Дополнение к ответу Игнасио Васкес-Абрамса. Это позволит знаку + предшествовать целому числу и позволит использовать любое количество нулей в качестве десятичных знаков. Например, это позволит считать +45.00000000 целым числом.
Однако $ 1 должен быть отформатирован так, чтобы содержать десятичную точку. 45 здесь не считается целым числом, а 45,0 - таковым.
источник
^[-+]?[0-9]
...?Для смеха я примерно быстро разработал набор функций для этого (is_string, is_int, is_float, is alpha string или другие), но есть более эффективные (меньше кода) способы сделать это:
Пройдя здесь несколько тестов, я определил, что -44 - это int, а 44- - нет и т. Д .:
Вывод:
ПРИМЕЧАНИЕ: ведущие 0 могут означать что-то еще при добавлении чисел, таких как восьмеричное, поэтому было бы лучше удалить их, если вы намерены рассматривать '09' как int (что я делаю) (например,
expr 09 + 0
или разделить с помощью sed)источник