Как передать список файлов, возвращаемых командой find для просмотра всех файлов

204

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

Деванг Камдар
источник

Ответы:

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

    command1 | command2
    

    Это отправит вывод command1 как ввод command2

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

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

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

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

    command2 `command1`
    

    например:

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

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

kenj0418
источник
2
кот find -name '*.foo' -printотлично сработал для меня ... Спасибо
Деванг Камдар
Обратные кавычки работают отлично и более обобщенно, вы также можете использовать это для вывода списка файлов из файла.
Хазок
11
Обратите внимание, что современные версии findпозволяют писать:, find . -name '*.foo' -exec cat {} +где +указывает, что findследует объединить столько имен файлов, сколько это удобно, в один вызов команды. Это очень полезно (оно работает с пробелами и т. Д. В именах файлов, не прибегая к -print0и xargs -0).
Джонатан Леффлер
18
Без упоминания:find . -name '*.foo' | xargs cat
stewSquared
3
Просто чтобы добавить ответ @stewSquared: чтобы найти все строки в файлах, которые содержат определенную строку, сделайтеfind . -name '*.foo' | xargs cat | grep string
Bim
84

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

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командную строку, чтобы всегда было как минимум два имени файла.

Джонатан Леффлер
источник
Для тех, кто запутался, как я, обратите внимание, что этот способ сначала выдаст весь вывод find, а затем выдаст вывод xargs grep something.
Эрик Ху,
3
@EricHu: Я вижу, что вы в замешательстве, но он не делает то, о чем вы говорите, по крайней мере, не в любой Unix-системе, о которой я знаю. Вывод findпередается на стандартный ввод xargs. xargsПрограмма считывает стандартный ввод, разделяя вход в пустое пространство (пробелы, новые строки, вкладки и т.д.) и добавляет число слов в команду grep somethingи выполняет командную строку. xargsзатем продолжает чтение ввода и выполнение команд, пока не закончится ввод. xargsзапускает grepкоманду так часто, как это необходимо для вводимого ею ввода (из findэтого примера).
Джонатан Леффлер
Ах, моя ошибка, это использование grep для поиска в каждом найденном файле. Я хотел просто отфильтровать вывод find с помощью grep
Eric Hu
1
Ошибки переходят к стандартной ошибке (дескриптор файла 2) для всех команд с хорошим поведением. Перенаправление stderr на /dev/nullтеряет сообщения об ошибках.
Джонатан Леффлер
1
Это также имеет то преимущество, что лучше работает с пробелами в пути к файлу. Даже `sed'ing" "->" \ "разбивает его на`, но с xargs он работает отлично
JZL003
36

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

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

    cat `find [whatever]`
    

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

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

    cat $(find [whatever])
    

    Это менее переносимо, но является вложенным. Помимо этого, он имеет почти те же предостережения, что и кавычки.

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

    find [whatever] -exec cat {} \;
    

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

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

  4. Некоторые версии find( в первую очередь в версии GNU) позволяют заменить ;с +для использования -exec« в режиме S дописывания для запуска меньше случаев 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... +, хотя и более переносимо (но, к сожалению, более многословно).

Лоуренс Гонсалвес
источник
Метод backtick хорош, потому что он работает и для других команд ls.
Мартин Браун
@Martin Braun с использованием $()Также работает с командами, кроме find .
Лоуренс Гонсалвес
Спасибо, приятно знать, что я перестал читать после (1), потому что это удовлетворяет мои потребности, так как я не имею дело со специальными символами, такими как пробелы и тому подобное.
Мартин Браун
9

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

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

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

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

Stphane
источник
6

Похоже, работа для сценария оболочки для меня:

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

или что-то вроде того

Гэндальф
источник
2
Это верный, хотя и не обязательно оптимальный ответ на вопрос.
Джонатан Леффлер
1
... да, но это здорово, если вам нужен один большой файл с именами файлов.
ʍǝɥʇɐɯ
1
Мне нравится это лучше всего. Блок цикла, подобный этому, оставляет место для других дел.
Каке
4

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

find . -name \*.xml | while read i; do grep '<?xml' "$i" >/dev/null; [ $? == 0 ] && echo $i; done
Greg
источник
3

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

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

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

ekinak
источник
2

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

grep YOURSTRING `find .`

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

zakki
источник
2

В 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команду from find.

Макклейн Луни
источник
0

Это работает для меня

find _CACHE_* | while read line; do
    cat "$line" | grep "something"
done
Стивен Пенни
источник
0

Используйте ggrep .

ggrep -H -R -I "mysearchstring" *

искать файл в unix, содержащий текст, расположенный в текущем каталоге или подкаталоге

Underverse
источник
0

Это напечатает имя и содержимое файлов только рекурсивно.

find . -type f -printf '\n\n%p:\n' -exec cat {} \;

Редактировать (улучшенная версия): будет рекурсивно печатать имя и содержимое текстовых (ascii) файлов.

find . -type f -exec grep -Iq . {} \; -print | xargs awk 'FNR==1{print FILENAME ":" $0; }'

Еще одна попытка

find . -type f -exec grep -Iq . {} \; -printf "\n%p:" -exec cat {} \;
Прашант Адлинге
источник
-1

Вы пытаетесь найти текст в файлах? Вы можете просто использовать grep для этого ...

grep searchterm *
Скотт Андерсон
источник
-1

Для просмотра и просмотра содержимого всех файлов abc.def на сервере в каталогах / ghi и / jkl

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec ls {} \; -exec cat {} \;

Чтобы просмотреть список файлов abc.def с комментариями и отображением, смотрите эти записи в каталогах / ghi и / jkl

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec grep -H ^# {} \;
Sharjeel
источник