Почему “grep keyword” заставляет терминал ждать бесконечно?

Вопрос или проблема

Когда я ввожу “grep doc” в терминале, это просто ничего не делает, останавливая терминал от любых других действий, пока я не выйду с помощью Ctrl+C или Z.

Я знаю, что это не правильный способ использования grep, но мне просто интересно, почему это происходит.

grep по умолчанию ищет в стандартном вводе, если файлы не указаны:

grep ищет в указанных входных файлах (или в стандартном вводе, если файлы не указаны, или если в качестве имени файла указан одиночный дефис) строки, содержащие совпадение с заданным ПАТТЕРНОМ. По умолчанию grep выводит совпадающие строки.

Если вы просто делаете grep doc, grep ожидает стандартный ввод и ищет в нем (не вводите части между < и > в терминале, это комментарии):

$ grep doc
a b c <НАЖМИТЕ ENTER ЗДЕСЬ>
doc <СОВПАДЕНИЕ НЕ НАЙДЕНО В ПРЕДЫДУЩЕЙ СТРОКЕ, ВВЕДИТЕ doc И НАЖМИТЕ ENTER СНОВА>
doc <СОВПАДЕНИЕ НАЙДЕНО>

grep завершится, когда увидит конец файла на своем вводе. Когда это устройство tty и предполагая, что оно находится в режиме icanon (что должно быть по умолчанию), способ обозначить конец файла — нажать Ctrl+d¹ на пустой строке или нажать его дважды (в этом случае текущая строка будет передана в grep без разделителя, за которым следует конец файла).


¹ Или любая другая клавиша или комбинация клавиш, отправляющая символ eof, по умолчанию ^D, ищите eof = ... в выходных данных stty -a.

grep ожидает ввода.

Из man grep:

[...]
ОПИСАНИЕ
       grep  ищет в указанных входных файлах (или в стандартном вводе, если файлы не указаны)
[...]

Описание этого поведения в руководстве GNU grep 3.4 в Ubuntu 20.04. Из man grep:

СИНТАКСИС

   grep [ОПЦИЯ...] ПАТТЕРНЫ [ФАЙЛ...]
   grep [ОПЦИЯ...] -e ПАТТЕРНЫ ... [ФАЙЛ...]
   grep [ОПЦИЯ...] -f ПАТТЕРНЫЙ_ФАЙЛ ... [ФАЙЛ...]

ОПИСАНИЕ

grep ищет ПАТТЕРНЫ в каждом ФАЙЛЕ. ПАТТЕРНЫ — это один или несколько паттернов, разделенных символами новой строки, и grep выводит каждую строку, которая соответствует паттерну. Обычно ПАТТЕРНЫ следует заключать в кавычки, когда grep используется в командной оболочке.

ФАЙЛ «-» обозначает стандартный ввод. Если ФАЙЛ не указан, рекурсивные поиски проверяют рабочий каталог, а нерекурсивные читают стандартный ввод.

Сначала я неправильно понял фразу:
“If no FILE is given, recursive searches examine the working directory, and nonrecursive searches read standard input.”

Я думал, что это означало что-то вроде следующего: “If no FILE is given, recursively examine the working directory, and nonrecursively read standard input”. И думал, что в этом есть ошибки и неточности.

Но это не так. Спасибо Stéphane Chazelas за то, что указал на это. Эта фраза точна и означает следующее: Если ФАЙЛ не указан, рекурсивные поиски (grep с опцией -r) проверяют рабочий каталог; нерекурсивные поиски (без опции -r) читают стандартный ввод.

grep keyword (нерекурсивный поиск) ожидает ввода из стандартного ввода и, из-за этого, как будто зависает на неопределенное время, хотя на самом деле он читает ввод с клавиатуры (до конца файла, что может быть обозначено с помощью Ctrl + d, хотя вы также можете прервать его с помощью Ctrl + c).

-r может быть добавлено для рекурсивного чтения файлов в текущем рабочем каталоге и не ожидания стандартного ввода: grep -r keyword (рекурсивный поиск), хотя явное указание . сделает его более переносимым (для более старых версий GNU grep или других реализаций grep, которые скопировали это нестандартное расширение -r от GNU grep).

Это поведение также описано в man grep для опции -r:


-r, --recursive
Читать все файлы под каждым каталогом, рекурсивно, следуя символическим ссылкам только если они указаны в командной строке. Заметьте, что если операнд файла не указан, grep выполняет поиск в рабочем каталоге.
Это эквивалентно опции -d recurse. …

Или форма grep keyword ./* может использоваться для поиска чего-то во всех неневидимых файлах текущего каталога, но без рекурсии.

.

Ответ или решение

Команда grep keyword, когда она используется без указания конкретного файла для поиска, вызывает зависание терминала, ожидая ввода данных от пользователя. Это поведение весьма вероятно вызывает замешательство, особенно если вы не знакомы с работой команд UNIX/Linux.

Объяснение (Теория)

По умолчанию команда grep предназначена для поиска заданного паттерна в файле или потоке данных. Если файл не указан, grep предполагает, что данные будут поступать из стандартного ввода (stdin). Это автоматически переводит команду в режим ожидания ввода, который инициируется вами через терминал.

Пример

Когда вы вводите grep doc в терминале, если не указан ни один файл, команда grep ожидает, что данные, в которых нужно искать doc, поступят от вас. Пока ввод не завершён (например, с помощью клавиш Ctrl+D, указывающего на конец ввода), grep остается в состоянии ожидания.

Доподлинно убедиться в этом вы можете следующим образом:

$ grep doc
a b c <нажмите ENTER>
doc <нажмите ENTER, чтобы ввести строку>
doc <результат: строка найдена>

Применение

Если ваша цель — найти слово doc в файлах, вам нужно указать файлы явно или использовать опцию для рекурсивного поиска. Например, с помощью команды grep -r doc . можно будет осуществить поиск в текущем каталоге и всех его подкаталогах. Использование команды grep doc ./* позволит выполнить поиск в каждом файле текущего каталога без рекурсии.

Это основывается на стандартах работы командной строки в UNIX/Linux и позволяет избежать ситуаций, когда терминал, казалось бы, зависает. Для успешного применения команд grep требуется ясное понимание их работы с потоками ввода-вывода, что позволит вам избегать подобных проблем в будущем.

Оцените материал
Добавить комментарий

Капча загружается...