Grep только первый матч и остановка


329

Я рекурсивно ищу каталог, используя grep со следующими аргументами, надеясь вернуть только первое совпадение. К сожалению, он возвращает больше, чем один - фактически два раза, когда я смотрел в последний раз. Кажется, у меня слишком много аргументов, особенно без желаемого результата. : - /

# grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/directory

возвращает:

Pulsanti Operietur
Pulsanti Operietur

Может быть, grep не лучший способ сделать это? Вы говорите мне, большое спасибо.

Ответы:


512

-m 1означает вернуть первое совпадение в любой файл. Но он все равно продолжит поиск в других файлах. Кроме того, если есть две или более совпавших в одной строке, все они будут отображаться.

Вы можете использовать head -1для решения этой проблемы:

grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -1

объяснение каждого варианта grep:

-o, --only-matching, print only the matched part of the line (instead of the entire line)
-a, --text, process a binary file as if it were text
-m 1, --max-count, stop reading a file after 1 matching line
-h, --no-filename, suppress the prefixing of file names on output
-r, --recursive, read all files under a directory recursively

здорово! Спасибо. Кстати - все эти другие аргументы необходимы, которые я имею в команде? и что, если я не могу передать это случайно (на всякий случай).
Тим Камм

2
Я не думаю, что они необходимы (за исключением, -rочевидно), но они не должны причинять боль (я бы не использовал -a)
mvp

3
Именно то, что мне было нужно. Мой шаблон был найден дважды в одной строке и grep -m 1возвратил оба экземпляра из-за этого. |head -1решил это!
Harperville

6
@Chris_Rands, точное поведение зависит от оболочки, в которой вы работаете. Head выйдет, как только встретит первую строку. grep выйдет в следующий раз, когда попытается написать после выхода из головы. Некоторые оболочки будут ожидать завершения всех элементов конвейера, другие вызовут остановку всей трубы, как только закроется последняя программа в конвейере.
Пухлен

1
@ 3Qn, я не понимаю ваш комментарий: first not first from result. Этот ответ печатает первое совпадение в любом файле и останавливается. Что еще ты ожидал?
MVP

31

Вы можете передатьgrep результат headв сочетании с stdbuf .

Обратите внимание, что для того, чтобы обеспечить остановку после N-го совпадения, вам нужно использовать, stdbufчтобы убедиться, grepчто не буферизируют его вывод:

stdbuf -oL grep -rl 'pattern' * | head -n1
stdbuf -oL grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -n1
stdbuf -oL grep -nH -m 1 -R "django.conf.urls.defaults" * | head -n1

Как только headпотребляет 1 строку, он завершается и grepполучит, SIGPIPEпотому что он все еще выводит что-то в трубу, пока headпропало.

Предполагалось, что имена файлов не содержат символ новой строки.


Я пытаюсь принять это решение для поиска в большом количестве архивных файлов с xargs: find . -name '*.gz' | xargs -I '{}' stdbuf -oL zgrep -al 'pattern' {} | head -n 1. Это, однако, не заканчивается в первом матче. Любой совет?
DKroot

1
Не будет grep«s --line-bufferedопция предотвращает буфер накладных расходов , не вызывая дополнительную утилиту?
Дэвид

23

В моей программе grep-a-like ackесть -1опция, которая останавливается на первом найденном совпадении. Он поддерживает то, на -m 1что ссылается @mvp. Я вставил это туда, потому что, если я ищу большое дерево исходного кода, чтобы найти что-то, что, как я знаю, существует только в одном файле, нет необходимости его искать и нужно нажать Ctrl-C.


так вы бы сказали что ack быстрее чем grep? Я действительно обеспокоен фактором скорости тоже.
Тим Камм

1
Ack может быть быстрее, чем grep, в зависимости от того, что вы ищете. Обратите внимание, что ack - это поиск исходного кода. Если вы ищете для поиска общих файлов, это не очень хорошо, по крайней мере, в ack 1.x. Читайте об ack и посмотрите, может быть, он вам подходит.
Энди Лестер

2
Я давно пользуюсь Ack, но недавно перешел на Серебряный поисковик, который, как мне кажется, быстрее Ack
guy.gc

Я считаю, что это должен быть единственный ответ, потому что OP сказал, что хочет, чтобы это было сделано с помощью grep, но другой ответ использует head (обе работы, конечно), но есть некоторые встроенные / самостоятельно созданные среды с минимальными инструментами, где grep распространен и tail / голова нет.
Ариб Су Ясир

Стоит отметить , что agможет быть быстрым, но это не имеет -1вариант , который полезен в данном случае
JJA

4

Вы можете использовать команду ниже, если вы хотите напечатать всю строку и имя файла, если вхождение определенного слова в текущем каталоге вы ищете.

grep -m 1 -r "Not caching" * | head -1

2

Единственный лайнер, используя find:

find -type f -exec grep -lm1 "PATTERN" {} \; -a -quit

6
Это будет очень медленно, так как find создаст копию grep для каждого найденного файла. grep -rработает намного быстрее - это только одна копия, которая выполняет обратный путь в каталогах.
MVP

Правда; хотя find можно настроить так, чтобы он работал только с отфильтрованными результатами, что может сделать операцию намного быстрее, чем универсальный grep. Зависит от контекста.
Ям Маркович
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.