Может ли кто-нибудь объяснить, что происходит в этой строке bash пошагово? Я новичок и пытаюсь понять, как работает этот код, особенно из echo
:
read char; echo -e "YES\nNO\n" | grep -i $char
решение1
Команды в строке считывают строку в переменную char
, вероятно, в интерактивном режиме от пользователя.
Конвейер echo
+ grep
пытается определить, является ли введенная строка утвердительной или нет. Он делает это, сопоставляя слова YES
и NO
с введенной строкой (введенная строка является шаблоном), без учета регистра. Если пользователь вводит заглавный или строчный символ или подстроку, присутствующую в слове YES
, результатом будет YES
; если он вводит заглавный или строчный символ или подстроку, присутствующую в строке NO
, результатом будет NO
. Ввод чего-то вроде maybe
приведет к пустому выводу.
Недостатком этого подхода является то, что если пользователь вводит, например, .
, YES
и NO
будет соответствовать как grep
будет рассматривать точку как регулярное выражение, которое соответствует любому символу. Поскольку $char
не заключено в кавычки в вызове grep
, это также может вызвать атаку типа «отказ в обслуживании» против машины, если пользователь введет шаблон подстановки оболочки, такой как /*/*/*/*/../../../../*/*/*/*
input (пример взят изПоследствия для безопасности, если забыть заключить переменную в кавычки в оболочках bash/POSIX). Вы также можете вызвать запутанный вывод с помощью команды, введя eg -r -o -e . /
(будет выведен каждый символ каждого недвоичного файла на отдельной строке, перед которой будет указан путь к файлу, частью которого он является).
Код, который вы показываете, «странный и необычный», поскольку он использует пользовательский ввод как нечто, по сутикод, т.е. он использует пользовательский ввод какшаблон, и тесты статическиеданныепротив этого переменного шаблона. Это противоположно тому, что обычно делают, то есть берут ввод от пользователя и проверяют эти переменные данные против статического шаблона.
Чаще всего используется код следующего вида:
read -p 'Yes/[N]o: ' yesno
if [[ $yesno == [Yy]* ]]; then
# code for affirmative
else
# code for non-affirmative
fi
Код выше считывает строку от пользователя и проверяет, начинается ли она с символа y
или Y
с. Первая ветвь оператора if
будет взята, если это так, но else
в противном случае она будет взята по умолчанию.
Очевидно, вы также можете проверить все слово YES
или [Yy][Ee][Ss]
выполнить проверку без учета регистра, или выполнить правильный цикл ввода с проверкой:
while true; do
read -p 'Yes/No: ' yesno
if [ "$yesno" = Yes ] || [ "$yesno" = No ]; then
break
fi
echo 'Please enter "Yes" or "No"' >&2
done
# $yesno is either Yes or No here
(или что-то подобное).
Обратите внимание, что оба приведенных выше примера кода используют введенные пользователем данные исключительно как данные и никогда как шаблон.
Минимальная переработка вашей исходной команды во что-то немного идиоматическое (но функционально иное и, вероятно, не защищенное от дурака) превратит ее в
read yesno; printf '%s\n' "${yesno^^}" | grep -i -w -E 'yes|no'
Это вернет заглавные буквы YES
или NO
, если пользователь ввел yes
или no
. Это функционально отличается, поскольку требует от пользователя ввести что-то большее, чем просто e
для yes
, например.
решение2
Давайте рассмотрим каждую команду по очереди:
read char
Он будет считывать данные со стандартного ввода (обычно это клавиатура, но это может быть косвенный файл или конвейерный поток; см. ниже) и помещать полученные данные в переменную с именем char
.
echo -e "YES\nNO\n"
echo
отобразит на стандартном выводе (обычно на терминале) предоставленные параметры. Переключатель -e
(часто, но не всегда; echo
это проблематично с точки зрения последовательной реализации) позволяет e
экранировать определенные символы для выполнения некоторого элементарного форматирования. В данном случае используется \n
, который является экранированным n
, что является сокращением для n
ewline.
grep -i $char
grep
— это инструмент для поиска в предоставленном вводе, чтобы увидеть, есть ли совпадения для предоставленного шаблона. Переключатель -i
указывает, что i
поиск должен быть нечувствительным к регистру.
Между |
командами echo
и grep
находится «труба». Она соединяет вывод первой команды со вводом второй, что означает, что grep
будет выполняться поиск в этом корпусе шаблона, отраженного в содержимом переменной char
:
YES
NO
Практическим результатом этой последовательности команд является просмотр предоставленного ввода (предполагается, что на основе имени переменной это один символ, но это не проверяется). Если этот символ — Y
, E
, S
, y
, e
или s
, вывод будет YES
. Если этот символ — N
, O
, n
, или o
, вывод будет NO
. Однако если (например) ввод — yo
или ne
, то ничего не будет выведено.
Как было отмечено ранее, предположение о том, что входные данные представляют собой один символ, не проверяется. Это не единственный антишаблон в приведенной последовательности команд. Например, переменные не заключаются в кавычки, а инструмент регулярных выражений ( grep
) используется без проверки входных данных на наличие подстановочных знаков регулярных выражений.
решение3
«Символ» (скорее: строка) считывается из /dev/stdin
. Значение: вы его вводите.
Затем выводятся две строки на /dev/stdout
. Имеются в виду ваша консоль.
А затем с помощью конвейера («|») выполняется grep для получения версии ваших входных данных без учета регистра.
Это значит, что если вы введете «bar», то он просто завершится без какого-либо видимого вывода, но если вы введете, скажем, «y», то он выведет строку «ДА», скорее всего, даже выделив «Y».