Чи є більш простий спосіб зібрати всі файли під каталогом?


21

Коли я хочу шукати деяке вміст у цілому дереві, я використовую

find . -type f -print0 | xargs -0 grep <search_string>

Чи є кращий спосіб зробити це з точки зору продуктивності чи стислості?


2
@Downvoter: Раді вдосконалити це питання, якщо ви можете поділитися своїми проблемами.
Dancrumb

2
У багатьох версіях знаходження вбудовані xargs: find. -type f -exec fgrep <search_string> {} +
simpleuser

Відповіді:


42

Перевірте, чи grepпідтримується Ваша -rопція (для повторної роботи ):

grep -r <search_string> .

1
Так ... я щойно знайшов stackoverflow.com/questions/16956810/…, і це теж відповідь.
Dancrumb

додати коментар щодо --exclude-dirвиступу та у нас є переможець!
Dancrumb

1
Зауважте лише, що це не портативно, однак grepв останніх дистрибутивах FreeBSD та Linux це підтримують. А чому --exclude-dir? Ти не просив обшукати ціле дерево ?
Філіппос

Справедливий момент ... --exclude-dirнасправді корисний у моєму випадку використання (адже частини піддерева великі, але марні), і я запитав про продуктивність ... але ти маєш рацію, це не обов'язково.
Dancrumb

У цьому випадку я повинен додати, що IIRC --exclude-dirє ексклюзивним для GNU grep. (-:
Філіпос

13

Суб оптимальна відповідь: Замість того, щоб підключити висновок findв grep, ви можете просто запустити

find . -type f -exec grep 'research' {} '+'

і вуаля, одна команда замість двох!

пояснення:

find . -type f

знайти всі звичайні файли в межах.

-exec grep 'research'

греп 'дослідження'

{}

у знайденому імені файлу

'+'

використовувати одну команду для всіх імен файлів, а не один раз для імені файлу.

Nb: з ';'ним було б один раз на ім’я файлу.

Крім цього, якщо ви використовуєте це для обробки вихідного коду, ви можете заглянути ack , що робиться для легкого пошуку бітів коду.

ак

Редагувати:

Ви можете трохи продовжити це дослідження. По-перше, ви можете використовувати-name '' перемикач findпошуку для файлів із заданим шаблоном іменування.

Наприклад :

  • лише файли, які відповідають журналам: -name '*.log'

  • лише файли, що відповідають заголовкам c, але ви не можете дотримуватися великих чи малих літер для розширень свого файлу: -iname *.c

Nb: як для grepіack , то -iперемикач означає чутливо до регістру в цьому випадку.

У цьому випадку grep відображатиметься без кольору та без номерів рядків.

Ви можете змінити це за допомогою --colorі-n перемикачів і (Колір і рядки у файлах відповідно).

Зрештою, ви можете мати щось на кшталт:

find . -name '*.log' -type f -exec grep --color -n 'pattern' {} '+'

наприклад

$ find . -name '*.c' -type f -exec grep -n 'hello' {} '+' 
./test2/target.c:1:hello

5
ackчудово, і більш швидка версія ackє ag(срібний шукач, geoff.greer.fm/ag )
cfeduke

1
Я вважаю за краще це з фільтром, як -name '*.log'це швидше.
sdkks

@cfeduke Я не пробував цього, в основному тому, що ag не є частиною вкладних сховищ за замовчуванням на WSL (ти повинен працювати з тим, що у тебе є!)
П'єр-Антуан Гійом

Хитрість полягає в тому, щоб додати / dev / null до grep, щоб отримати ім'я файлу.
ChuckCottrill

Хитрість полягає в пошуку лише каталогів, а потім -exec grep / dev / null {} / *, щоб отримати всі файли з одним fork / exec в каталозі.
ChuckCottrill

12

Якщо ви хочете повторно записатись у підкаталоги:

grep -R 'pattern' .

-RВаріант не є стандартним варіантом, але підтримується більшість поширених grepреалізацій.


7
Використовуйте -rзамість того, -Rщоб пропустити символьні посилання, коли мова йде про GNU grep
αғsnιη

1
@AFSHIN Чому б ви не хотіли дотримуватися посилань?
Kusalananda

4
@ Кусалананда Рекурсія? Хоча grepя думаю, що поточні реалізації GNU сприймають рекурсії. Інакше це залежить від того, що ви маєте на увазі під «деревом».
Філіппос

2
@Philippos IMHO, няня для користувача - це не те, що grepпотрібно робити інструменту . Якщо у користувача в структурі каталогів є символьні петлі посилань, то це проблема користувача :-)
Kusalananda

3
@Kusalananda І якщо система забезпечила цикл? Ніколи не загубився в /sys/devices/cpu/subsystem/devices/cpu/subsystem/devices/cpu/...(-XI, як інструменти няні мене (якщо вони не надають дивну магію, яку вони називають "AI"). (-;
Philippos

5

Як зазначено вище -rабо -R(залежно від бажаної обробки символьної лінії), це швидкий варіант.

Однак -d <action>може бути корисним часом.

Приємно в тому, що -dце команда пропуск, яка замовчує "grep: directory_name: Є каталог", коли ви просто хочете сканувати поточний рівень.

$ grep foo * 
grep: q2: Is a directory 
grep: rt: Is a directory 

$ grep -d skip foo *  
$ 

і звичайно:

$ grep -d recurse foo * 
(list of results that don't exist because the word foo isn't in our source code
and I wouldn't publish it anyway).  
$ 

Цей -d skipваріант дійсно зручний у іншому сценарії, тому не потрібно 2> /dev/null. :)


0

Якщо ви маєте справу з великою кількістю файлів, grep працює швидше, якщо ви підрізаєте файли, які йому потрібно шукати, а не стискати всі файли в папках.

Я іноді використовую цей формат:

grep "primary" `find . | grep cpp$`

Знайдіть усі файли в папках .цього кінця в cpp. Потім перетягніть ці файли на "первинний".

Якщо ви хочете, ви можете продовжувати передавати ці результати в подальші греп-дзвінки:

grep "primary" `find . | grep cpp$` | grep -v "ignoreThis" | grep -i "caseInsensitiveGrep"

1
Бекстінг - це не найкраща сучасна практика, вони є лише застарілими
Крістофер

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