Як запустити find -exec?


477

Я хотів би знайти файли в поточному каталозі, які містять текст "chrome".

$ find . -exec grep chrome
find: missing argument to `-exec'

Що я роблю неправильно?



У менеfind: Only one instance of {} is supported with -exec ... +
Коста,

Відповіді:


710

Ви пропустили ;(втекли сюди, \;щоб запобігти інтерпретації оболонки) або a +і a {}:

find . -exec grep chrome {} \;

або

find . -exec grep chrome {} +

findвиконає grepі замінить {}знайдені імена файлів. Різниця між ;і +полягає в тому, що за ;допомогою grepкожного файлу виконується одна команда, тоді як з +максимально можливим числом файлів задано параметри grepодночасно.


30
Якщо ви використовуєте \; grep закінчення конструкції передається по одному файлу за раз, тому він не відображає ім'я файлу за замовчуванням, а лише відповідні рядки. Щоб отримати список файлів, замість цього додайте використовувати grep -lsвсередину конструкції find.
Калеб

9
find . -exec grep foo {} +покаже вам вихід , як цей./dir/file.py:from foo import bar
к.с.

10
find . -exec grep foo {} \;покаже вам такий вихідfrom foo import bar
сер

9
find . -exec grep -l foo {} +покаже вам вихід , як цей./dir/file.py
к.с.

8
find . -exec grep -l foo {} \;покаже вам вихід , як цей./dir/file.py
к.с.

46

Вам для цього зовсім не потрібно користуватися find; grep здатний впоратися з відкриттям файлів або з глобального списку всього в поточному каталозі:

grep chrome *

... або навіть рекурсивно для папки та всього, що знаходиться під нею:

grep chrome . -R

22
grep задихнеться, якщо розширення перейде на ARG_MAX. -R відвідає все, використовуючи функцію find, можна легше додати примітиви, щоб виключити певні файли (-імена тощо) або навіть не відвідати підрядки (-prune).
Мел

6
Хороші бали @Mel. Моя думка полягала в тому, що, швидше за все, запитуюча сторона робила речі складніші, ніж це потрібно було, вводячи, findколи grepможна виконати роботу, але в деяких випадках було б ефективніше використовувати пошук для уточнення списку файлів перед виходом на вулицю грепати.
Калеб

4
@Mel grepв такому випадку execне задихається .
Кріс Даун

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

1
@Yaba У моїй відповіді зазначено, як обробляти справи файлів, розповсюджених у підкаталогах.
Калеб

18
find . | xargs grep 'chrome'

Ви також можете зробити:

find . | xargs grep 'chrome' -ls

Перший показує рядки у файлах, другий лише перераховує файли.

Варіант Калеба - акуратніше, менше натискань клавіш.


11
Проблема xargsполягає в тому, що він очікує, що його вклад буде процитований своєрідним чином, findякий не дає результату. Тому find … | xargs …не працює, якщо у вас є імена файлів, що містять пробіли або \'".
Жиль

3
@Gilles Ви можете подолати цю проблему, використовуючи щось подібне, find . | xargs -n1 -iX grep "X" 'chrome'щоб аргументи подавались по черзі і цитувалися. Очевидно, це жахливо неефективний спосіб поводження з цим прикладом, але для деяких ситуацій це приємно.
Калеб

Для повноти слід також відзначити варіант -i для нечутливості випадку з 'grep'. Також є -інам у пошуку для нечутливості випадку.
Матвій

9
@Caleb: Єдиний 100% надійний спосіб xargsвпоратися з назви файлів Linux - це find ... -print0 | xargs -0використовувати NUL як роздільник. Альтернативно - xargs -d '\n'використання нового рядка в якості сепаратора, 99% надійність.
grawity

Я використовую це часто, але він не вдасться для дуже довгих списків імен файлів, і тоді знайти -exec стає переможцем.
Spacemoose

5

Знайти це один спосіб, і ви можете спробувати, the_silver_searcherтоді все, що вам потрібно зробити

ag chrome

Він буде шукати хром у всіх файлах (включати підкаталоги), і це швидше, ніж знайти


Є також pt (платиновий пошук, доступний на веб- сайті github.com/monochromegane/the_platinum_searcher ), який, IMHO, виконує цю роботу швидше - може не мати значення, якщо є лише кілька файлів.
Скакаючий Зайчик

1

Щоб переглянути список файлів замість рядків:

grep -l "chrome" *

або:

grep -r -l "chrome" .

1

Ось приклад того, як я зазвичай використовую find / exec ...

find  . -name "*.py" -print -exec fgrep hello {} \;

Це рекурсивно шукає всі файли .py та для кожного друку (файлів) друкує ім'я файлу та fgrep для "привіт" у цьому (для кожного) файлі. Вихідний вигляд виглядає як такий (щойно пройшов сьогодні):

./r1.py
./cgi-bin/tst1.py
print "hello"
./app/__init__.py
./app/views.py
./app/flask1.py
./run.py
./tst2.py
print "hello again"

1
не возитися з вашим робочим процесом, але вам може сподобатися: find . -name "*.py" -exec fgrep -l hello {} \; - він надрукує файли файлів, які відповідають, і більше нічого
Jeff Schaller
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.