![bash-скрипт для проверки наличия @ во входных данных](https://rvso.com/image/1048309/bash-%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%20%D0%B4%D0%BB%D1%8F%20%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B8%20%D0%BD%D0%B0%D0%BB%D0%B8%D1%87%D0%B8%D1%8F%20%40%20%D0%B2%D0%BE%20%D0%B2%D1%85%D0%BE%D0%B4%D0%BD%D1%8B%D1%85%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85.png)
Привет, я пытаюсь написать скрипт bash, в котором входные данные проверяются на наличие символа @. Я относительно новичок в bash, поэтому, пожалуйста, простите за любые ошибки! Пока что у меня есть:
var1="@"
var2="INPUT"
echo "input"
read INPUT
if [[ "$var2" == "$var1" ]]; then
echo "pass"
else
echo "fail"
fi
решение1
Хотя у вас есть возможность использовать встроенную функциональность оболочки для проверки того, содержит ли ввод пользователя что-либо @
(что хорошо документировано в других ответах), другой разумный способ сделать это — использовать внешнюю оболочкуgrep
полезность:
#!/usr/bin/env bash
read -erp '> '
if grep -q @ <<<"$REPLY"; then
echo pass
else
echo fail
fi
Передача -q
флага grep
запрещает ему печатать совпадающие строки. (Это также не позволяет ему считывать дополнительные строки после нахождения совпадения, но в данном случае это не имеет значения, поскольку имеется только одна строка ввода.)
Возникает соблазн сократить if
конструкцию до чего-то вроде grep -q @ <<<"$REPLY" && echo pass || echo fail
, но я намеренно избегаю этого:
- В этом случае, это, вероятно, нормально, поскольку единственный способ, которым неправильное слово печатается, это если оно
pass
должно было быть напечатано, ноecho
не печаталось. Тогда, предположительно, echofail
также не печатается. - Хотя короткое замыкание
&&
и||
часто сами по себе уместны (и я часто использую их для сокращенияif
безпредложениеelse
), используя их вместе, как будто онитроичныйеслиоператорна самом деле не очень хорошая привычка. Хотя некоторые команды не могутнеудача,echo
может. - Если пользовательперенаправляетвывод вашего скрипта в неперезаписываемый файл или устройство или использование его в неисправномтрубопровод, echo и другие команды, выводящие текст, могут возвращать ошибку, что приводит к сбою выражения и выполнению
&&
правой части выражения .||
- Вы можете проверить поведение скрипта при наличии недоступного для записи устройства вывода, запустив его с помощью
>/dev/full
.
Этот скрипт использует несколько функций bash:
-e
включает GNU Readline, так что пользователь может перемещать курсор влево и вправо с помощью клавиш со стрелками, чтобы редактировать вводимые данные во время их ввода.- В bash
read
автоматически помещает введенные пользователем данные вREPLY
переменную, если переменная не указана. - Аздесь строкаwith
<<<
— это удобный способ передать введенные пользователем данные вgrep
. - Баш инекоторыйдругие оболочки в стиле Bourne, такие как dash accept
-p
. НоОболочки, совместимые с POSIX, должны понимать только-r
. А в некоторых, как ksh,-p
имеет другое значение.
(Спасибогейраза указание того, что-p
иногда отсутствуети чтоэто не всегда означает «быстро».)
Если вам нужен скрипт, который можно переносить на другие ОС, в которых может быть не установлен bash, вы можете использовать:
#!/bin/sh
printf '> '
read -r line
if printf '%s' "$line" | grep -q @; then
echo pass
else
echo fail
fi
Если хотите, вы можете пропустить сохранение введенных пользователем данных в переменной, прочитав их с помощьюhead
вместо read
:
#!/bin/sh
printf '> '
if head -1 | grep -q @; then
echo pass
else
echo fail
fi
Какгейра упомянула, head -n 1
можно считать лучшим синтаксисом, как head -1
естьофициально устарел(хотя текущие sed
реализации, или, по крайней мере, GNU sed, поддерживают -1
в своих последних версиях, в то время как некоторые очень старые sed
реализации не поддерживают -n 1
).
Какдокументацияhead
говорит, вы можете использовать sed
вместо этого для максимальной портативности.
#!/bin/sh
printf '> '
if sed 1q | grep -q @; then
echo pass
else
echo fail
fi
решение2
Этот bash
код считывает входные данные и выдает сигнал «Пройдено», если входные данные содержат @
символ:
read -p "Input: " var
[ "${var//[^@]/}" ] && echo Pass || echo Fail
Примечания:
[ "$var" ]
это тест bash. Он возвращает true, если строка$var
непустая.Одной из функций bash является подстановка шаблона. Выглядит как
${var//pattern/string}
. Он заменяет каждое вхождениеpattern
invar
наstring
. В нашем случаеpattern
это ,[^@]
которое является регулярным выражением, которое соответствует каждому символукроме@
. Таким образом,${var//[^@]/}
возвращается пустая строка, если онаvar
не содержит хотя бы одного@
.Мы объединяем два вышеперечисленных пункта:
[ "${var//[^@]/}" ]
Этот тест успешен только в том случае, если
${var//[^@]/}
непустой, и${var//[^@]/}
непустой только в том случае, еслиvar
содержит хотя бы один@
.
Использование явного if-then-else:
read -p "Input: " var
if [ "${var//[^@]/}" ]
then
echo Pass
else
echo Fail
fi
Оболочка POSIX
Следующее работает в dash
( /bin/sh
) и должно работать в любой оболочке POSIX:
printf "Input: "
read var
case "$var" in
*@*) echo Pass
;;
*) echo Fail
;;
esac
Оболочка POSIX не поддерживает -p
опциюread
. Таким образом, вместо этого используется комбинация printf
и . Кроме того, из-за отсутствия расширенных возможностей расширения переменных , оператор может использоваться для сопоставления glob.read
bash
case
Оболочка Android
Используя оболочку по умолчанию на моем Android, работает следующее:
echo -n "Input: "; read var
if ! [ "${var//@/}" = "$var" ]
then
echo Pass
else
echo Fail
решение3
Предпочтительным способом в bash является использование функции сопоставления с образцом [[ ... ]]
.
#bash
read -rp "Input: " input
if [[ $input = *@* ]]; then
printf '<%s> contains @\n' "$input"
fi
Для sh
скриптов вы можете использовать case
вместо этого.
#sh
printf 'Input: '
read -r input
case $input in
*@*) printf '<%s> contains @\n' "$input" ;;
esac
Смотрите такжеТесты и условные предложенияглава руководства Bash.
решение4
В новых версиях bash вы сможете использоватьрегулярное выражение совпадениечерез =~
расширенный тестовый оператор:
$ read -p "input: " input
input: quertyuiop
$ if [[ $input =~ \@ ]]; then echo "match"; else echo "no match"; fi
no match
$
$ read -p "input: " input
input: qwerty@uiop
$ if [[ $input =~ \@ ]]; then echo "match"; else echo "no match"; fi
match
Альтернативой, которая должна работать в любой совместимой с POSIX системе, является использование, expr
например, в dash
оболочке:
$ read input
qwertyuiop
$ if expr "$input" : '.*@.*' > /dev/null; then echo 'match'; else echo 'no match'; fi
no match
$
$ read input
qwerty@uiop
$ if expr "$input" : '.*@.*' > /dev/null; then echo 'match'; else echo 'no match'; fi
match
$