Вопрос или проблема
Когда я ввожу “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
требуется ясное понимание их работы с потоками ввода-вывода, что позволит вам избегать подобных проблем в будущем.