Понимание команд read, echo и grep в командной строке bash

Понимание команд read, echo и grep в командной строке bash

Может ли кто-нибудь объяснить, что происходит в этой строке 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, что является сокращением для newline.

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».

Связанный контент