Майте лише перший матч і зупиняйтеся


328

Рекурсивно шукаю каталог, використовуючи grep із наведеними нижче аргументами, сподіваючись повернути лише першу відповідність. На жаль, він повертається не один - фактично два востаннє, коли я дивився. Схоже, у мене занадто багато аргументів, особливо не отримуючи бажаного результату. : - /

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

повертає:

Pulsanti Operietur
Pulsanti Operietur

Можливо, греп - це не найкращий спосіб зробити це? Ви мені кажете, дуже дякую.

Відповіді:


510

-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

приголомшливий! Дякую тобі. btw - чи потрібні всі ті інші аргументи, які я маю в команді? і що робити, якщо я не можу це зробити випадково (про всяк випадок).
Тім Камм

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

3
Саме те, що мені було потрібно. Мій шаблон був знайдений двічі в одному рядку і grep -m 1через це повернув обидва екземпляри. |head -1вирішив це!
harperville

6
@Chris_Rands точна поведінка залежить від оболонки, в якій ви працюєте. Голова вийде, як тільки зустріне перший рядок. grep вийде наступного разу, коли він спробує записати після виходу голови. Деякі оболонки будуть чекати, поки всі елементи трубопроводу закінчаться, а інші призведуть до відключення всієї труби, як тільки вийде остання програма в трубі.
puhlen

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

Моя програма, ackяка подобається, має -1варіант, який зупиняється на першому знайденому в будь-якому місці. Він підтримує те, на -m 1що посилається і @mvp. Я вкладаю його туди, тому що якщо я шукаю велике дерево вихідного коду, щоб знайти те, що, наскільки я знаю, існує лише в одному файлі, його зайве знайти і потрібно натиснути Ctrl-C.


тож ви б сказали, що ак швидший за греп? Мене теж дуже хвилює коефіцієнт швидкості.
Тім Камм

1
ack може бути швидше, ніж grep, залежно від того, що ви шукаєте. Зауважте, що в ack йдеться про пошук вихідного коду. Якщо ви хочете шукати загальні файли, це менш добре, принаймні, в ack 1.x. Перейдіть почитайте про ack і подивіться, чи можливо він відповідає вашим потребам.
Енді Лестер

2
Я довго користувався Ack, але нещодавно перейшов на «Срібний пошук», який я вважаю швидшим Ack
guy.gc

Я вважаю, що це має бути єдиною відповіддю, тому що ОП заявив, що хоче, щоб це було зроблено з grep, але в іншій відповіді використовується голова (обидві роботи, звичайно), але є деякі вбудовані / створені власноруч середовища з мінімальними інструментами, де grep є звичайним та хвостом / голова - ні.
Areeb Soo Yasir

Варто згадати, що це agможе бути швидким, але він не має -1можливості, яка корисна в цьому випадку
jja

3

Ви можете використовувати команду нижче, якщо ви хочете надрукувати весь рядок та ім'я файлу, якщо зустрічається певне слово у поточному каталозі, який ви шукаєте.

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

2

Один вкладиш, використовуючи find:

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

6
Це буде дуже повільним, оскільки пошук породжує копію grep для кожного знайденого файлу. grep -rпрацює набагато швидше - єдина його копія, яка робить обхід каталогів.
mvp

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