Як ігнорувати певні назви файлів, використовуючи "знайти"?


143

Одна з моїх улюблених команд BASH:

find . -name '*.*' -exec grep 'SearchString' {} /dev/null \;

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

Однак, завдяки моєму поточному проекту та структурі моєї кодової бази, я хотів би зробити цю команду BASH ще більш вдосконаленою, не шукаючи жодних файлів, що знаходяться в каталозі, що знаходиться в ньому або нижче, або "будь-яких файлів, що містять" .svn " закінчується ".html"

Сторінка MAN для пошуку свого роду збентежила мене. Я спробував використовувати -prune, і це викликало дивну поведінку. Намагаючись пропустити лише сторінки .html (для початку), я спробував:

find . -wholename './*.html' -prune -exec grep 'SearchString' {} /dev/null \;

і не отримав тієї поведінки, на яку я сподівався. Я думаю, що я, можливо, пропускаю точку -пріну. Ви можете мені допомогти?

Дякую


1
Just fyi: findце не команда bash, що
вбудовується,

1
Ви можете шукати всередині файлу зgrep -rl 'SearchString'
emanuele

@emanuele Привіт, ласкаво просимо до SuperUser (та мережі Stack Exchange). Це запитання, яке я задав, і на нього відповіли 2 1/2 роки тому. Як правило, якщо ви хочете додати відповідь на запитання, будь ласка, зробіть це, прокручуючи донизу і відповідаючи там, замість коментаря. Оскільки на це питання вже є прийнята відповідь (відповідь із зеленою галочкою), навряд чи ваша відповідь буде привертати багато уваги. FYI.
Cody S

1
Привіт, це не відповідь на ваше запитання. Це лише підказка, як ви сказали в преамбулі, яка використовується findдля пошуку всередині файлу.
emanuele

2
FWIW -name '*.*'не знайде всіх файлів: лише ті, у кого .їх ім'я ( *.*як правило, це DOS-ism, тоді як в Unix ви зазвичай використовуєте саме *для цього). Для того, щоб дійсно відповідати їх все, просто видаліть аргумент взагалі: find . -exec .... Або якщо ви хочете застосувати grep лише до файлів (і пропустити каталоги), тоді це зробити find . -type f -exec ....
Стефан

Відповіді:


197

Ви можете використовувати функцію nete (!) Знаходження, щоб не збігати файли з конкретними іменами:

find . ! -name '*.html' ! -path '*.svn*' -exec grep 'SearchString' {} /dev/null \;

Отже, якщо ім'я закінчується в .html або містить .svn в будь-якому місці шляху, воно не збігатиметься, і тому exec не буде виконуватися.


1
Чи потрібно все-таки вказати -name ' . 'десь там? Я би робив це до, або після негативів?
Cody S

Чи був намір вашого *.*матчу забезпечити лише відповідні файли, що містять a .? Знайти відповідатиме всім файлам за відсутності nameдирективи, тому вищезгадане відповідатиме всім, окрім html та svn
Paul

5
Я думаю, що ви хочете, -wholename '*.svn*'а не -name.
fuenfundachtzig

2
Так, так, щоб .svnкаталоги були виключені з результатів пошуку.
fuenfundachtzig

1
@Noumenon ! -name '.'повинен виключити .з результатів пошуку.
Пол

11

У мене було одне і те ж питання давно, і є кілька рішень, які можуть бути застосовні в різних ситуаціях:

  • ack-grepце свого роду "розробник grep", який за замовчуванням пропускає каталоги управління версіями та тимчасові файли. На manсторінці пояснено, як шукати лише певні типи файлів та як визначити свій власний .
  • grepвласні --excludeта --exclude-dirпараметри можуть бути використані дуже просто для пропуску файлових глобусів та одиночних каталогів (на жаль, немає глобалізації для каталогів).
  • find . \( -type d -name '.svn' -o -type f -name '*.html' \) -prune -o -print0 | xargs -0 grep ... повинен працювати, але вищезазначені варіанти, мабуть, менше клопоту в довгостроковій перспективі.

9

Наступна findкоманда виконує обрізки каталогів, імена яких містять .svn , хоча вона не спускається до каталогу, ім'я обрізаного шляху друкується ... ( -name '*.svn'це причина!) ..

Ви можете відфільтрувати імена каталогів через: grep -d skipякий мовчки пропускає такі вхідні "імена каталогів".

За допомогою GNU grep ви можете використовувати -Hзамість /dev/null. Як незначне побічне питання: \+може бути набагато швидшим, ніж \;, наприклад, для 1 мільйона однорядкових файлів, використовуючи \;його, потрібно 4m20s , а для \+його використання було лише 1,2s .

Наступний метод використовує xargsзамість цього -execі передбачає, що \nв жодному з ваших імен файлів немає нових рядків . Як тут використовується, xargsмайже все одно, що і знахідка \+.

xargsможе передати файл-імена , які містять пробілу поспіль, змінюючи вхідний роздільник '\n'з -dопцією.

Це виключає каталоги, чиї назви містять, .svn і видаляє лише ті файли, які не закінчуються .html.

find . \( -name '*.svn*' -prune  -o ! -name '*.html' \) |
   xargs -d '\n' grep -Hd skip 'SearchString'

1
Дякуємо, що вказали на \+варіант дії -exec. Ура за незначні побічні проблеми!
Крістіан Лонг

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