Как передать список файлов, возвращаемых командой find для просмотра всех файлов - PullRequest
184 голосов
/ 14 мая 2009

Я делаю find, а затем получаю список файлов. Как передать его в другую утилиту, такую ​​как cat (чтобы cat отображала содержимое всех этих файлов), и в основном нужно grep что-то из этих файлов.

Ответы [ 15 ]

299 голосов
/ 14 мая 2009
  1. Трубопровод к другому процессу (хотя это НЕ ПОЛУЧИТ то, что, как вы сказали, вы пытаетесь сделать):

    command1 | command2
    

    Это отправит вывод команды 1 в качестве ввода команды 2

  2. -exec на find (это будет делать то, что вы хотите сделать, но относится только к find)

    find . -name '*.foo' -exec cat {} \;
    

    (Все между find и -exec являются предикатами поиска, которые вы уже использовали. {} заменит конкретный файл, который вы нашли в команде (cat {} в данном случае); \; - завершить команду -exec.)

  3. отправлять вывод одного процесса в качестве аргументов командной строки другому процессу

    command2 `command1`
    

    например:

    cat `find . -name '*.foo' -print`
    

    (Обратите внимание, что это ЗАДНИЕ ЦИТАТЫ, а не обычные кавычки (под тильдой ~ на моей клавиатуре).) Это отправит вывод command1 в command2 в качестве аргументов командной строки. Обратите внимание, что имена файлов, содержащие пробелы (переводы строк и т. Д.), Будут разбиты на отдельные аргументы.

78 голосов
/ 14 мая 2009

Современная версия

POSIX 2008 добавил маркер + к find, что означает, что теперь он автоматически группирует столько файлов, сколько целесообразно, в одно выполнение команды, очень похоже на xargs, но с ряд преимуществ:

  1. Вам не нужно беспокоиться о нечетных символах в именах файлов.
  2. Вам не нужно беспокоиться о том, что команда вызывается с нулевыми именами файлов.

Проблема с именем файла - это проблема с xargs без опции -0, а проблема «даже с нулевыми именами файлов» - с или без опции -0, но GNU xargs имеет опция -r или --no-run-if-empty, чтобы предотвратить это. Кроме того, эта запись сокращает количество процессов, а не то, что вы, скорее всего, будете измерять разницу в производительности. Следовательно, вы могли бы разумно написать:

find . -exec grep something {} +

Классическая версия

find . -print | xargs grep something

Если вы работаете в Linux или у вас есть команды GNU find и xargs, используйте -print0 с find и -0 с xargs для обработки имен файлов, содержащих пробелы и другие нечетные символы символы.

find . -print0 | xargs -0 grep something

Настройка результатов от grep

Если вам не нужны имена файлов (только текст), добавьте соответствующую опцию к grep (обычно -h для подавления «заголовков»). Чтобы абсолютно гарантировать, что имя файла напечатано с помощью grep (даже если найден только один файл или при последнем вызове grep дается только 1 имя файла), добавьте /dev/null в командную строку xargs, чтобы всегда было как минимум два имени файла.

34 голосов
/ 14 мая 2009

Существует несколько способов передать список файлов, возвращаемых командой find, в команду cat, хотя технически не все используют конвейерную передачу, и ни один из них не передает непосредственно к cat.

  1. Самое простое - использовать обратные метки (`):

    cat `find [whatever]`
    

    Это берет вывод find и эффективно помещает его в командную строку cat. Это не работает, если find имеет слишком много выходных данных (больше, чем может поместиться в командной строке) или если выходные данные содержат специальные символы (например, пробелы).

  2. В некоторых оболочках, включая bash, вместо обратных галочек можно использовать $():

    cat $(find [whatever])
    

    Это менее переносимо, но нестабильно. Кроме того, он имеет почти те же предостережения, что и обратные помехи.

  3. Поскольку выполнение других команд для обнаруженного является распространенным использованием find, команда find имеет действие -exec, которое выполняет команду для каждого найденного файла:

    find [whatever] -exec cat {} \;
    

    {} является заполнителем для имени файла, а \; отмечает конец команды (возможно выполнение других действий после -exec.)

    Это будет запускать cat один раз для каждого отдельного файла, а не запускать один экземпляр cat, передавая ему несколько имен файлов, что может быть неэффективно и может не соответствовать желаемому поведению некоторых команд (хотя это хорошо для * 1040). *). Синтаксис также неудобен для ввода - вам нужно избегать точки с запятой, потому что точка с запятой является особенной для оболочки!

  4. Некоторые версии find (особенно версия GNU) позволяют заменить ; на +, чтобы использовать режим добавления -exec для запуска меньшего числа экземпляров cat:

    find [whatever] -exec cat {} +
    

    Это передаст несколько имен файлов каждому вызову cat, что может быть более эффективным.

    Обратите внимание, что это не , однако гарантированно использовать один вызов. Если командная строка будет слишком длинной, то аргументы будут распределены по нескольким вызовам cat. Для cat это, вероятно, не имеет большого значения, но для некоторых других команд это может изменить поведение нежелательным образом. В системах Linux ограничение длины командной строки довольно велико, поэтому разбиение на несколько вызовов довольно редко по сравнению с некоторыми другими ОС.

  5. Классический / переносной подход заключается в использовании xargs:

    find [whatever] | xargs cat
    

    xargs запускает указанную команду (cat, в данном случае) и добавляет аргументы на основе того, что она читает из стандартного ввода. Как и -exec с +, это приведет к разрыву командной строки при необходимости. То есть, если find выдает слишком много вывода, он будет запускаться cat несколько раз. Как упоминалось в разделе о -exec ранее, есть некоторые команды, в которых это разделение может привести к другому поведению. Обратите внимание, что использование xargs, как это, имеет проблемы с пробелами в именах файлов, так как xargs просто использует пробел в качестве разделителя.

  6. Самый надежный, портативный и эффективный метод также использует xargs:

    find [whatever] -print0 | xargs -0 cat
    

    Флаг -print0 указывает find использовать \0 (нулевой символ) разделители между именами файлов, а флаг -0 указывает xargs ожидать этих \0 разделителей. Это поведение в значительной степени идентично поведению -exec ... +, хотя и более переносимо (но, к сожалению, более многословно).

9 голосов
/ 12 сентября 2012

Для этого (используя bash) я бы сделал следующее:

cat $(find . -name '*.foo')

Это называется «подстановкой команд» и по умолчанию удаляет перевод строки, что действительно удобно!

больше информации здесь

6 голосов
/ 14 мая 2009

Для меня это звучит как работа для сценария оболочки:

for file in 'find -name *.xml'
do
   grep 'hello' file
done

или что-то в этом роде

4 голосов
/ 18 мая 2013

Вот мой способ найти имена файлов, которые содержат интересующий меня контент, всего лишь одну строку bash, которая также хорошо обрабатывает пробелы в именах файлов:

find . -name \*.xml | while read i; do grep '<?xml' "$i" >/dev/null; [ $? == 0 ] && echo $i; done
3 голосов
/ 30 ноября 2016

Я использую что-то вроде этого:

find . -name <filename> -print0 | xargs -0 cat | grep <word2search4>

Аргумент "-print0" для аргументов "find" и "-0" для "xargs" необходим для правильной обработки пробелов в путях / именах файлов.

2 голосов
/ 30 мая 2012

Вот мой снимок для общего пользования:

grep YOURSTRING `find .`

Будет напечатано имя файла

2 голосов
/ 14 апреля 2011

В bash подойдет следующее:

find /dir -type f -print0 | xargs -0i cat {} | grep whatever

Это найдет все файлы в каталоге /dir и безопасно передаст имена файлов в xargs, что безопасно приведет к grep.

Пропуск xargs не очень хорошая идея, если у вас есть много тысяч файлов в /dir; cat сломается из-за чрезмерной длины списка аргументов. xargs разберутся за вас.

Аргумент -print0 для find соответствует аргументу -0 для xargs для правильной обработки имен файлов с пробелами. Аргумент -i для xargs позволяет вам вставить имя файла, где это необходимо, в командной строке cat. Скобки заменяются именем файла, переданным в команду cat из find.

2 голосов
/ 14 мая 2009

Команда find имеет аргумент -exec, который вы можете использовать для таких вещей, вы можете просто использовать grep напрямую, используя это.

Например ( здесь, другие хорошие примеры на этой странице ):

find . -exec grep "www.athabasca" '{}' \; -print 
...