Как вы справляетесь с проблемой "Слишком много файлов" при работе в Bash?

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

grep foo *

Я получаю слишком много сообщений об ошибках файлов, поэтому в итоге я делаю

for i in *; do grep foo $i; done

или

find ../path/ | xargs -I{} grep foo "{}"

Но они менее оптимальны (создайте новый процесс grep для каждого файла).

Это больше похоже на ограничение размера аргументов, которое могут получить программы-программы, так как * в цикле for работает нормально. Но, в любом случае, какой правильный способ справиться с этим?

PS: Не говорите мне делать grep -r вместо этого, я знаю об этом, я думаю о инструментах, которые не имеют рекурсивного варианта.

Ответ 1

В новых версиях findutils find может выполнять работу xargs (включая поведение glomming, так что используется только столько обработок grep, сколько необходимо):

find ../path -exec grep foo '{}' +

Использование +, а не ;, поскольку последний аргумент вызывает это поведение.

Ответ 2

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

find . -print0 | xargs -0 grep -H foo

Ответ 3

xargs не запускает новый процесс для каждого файла. Он объединяет аргументы. Посмотрите параметр -n на xargs - он контролирует количество аргументов, переданных каждому выполнению подкоманды.

Ответ 4

Я не вижу, что

for i in *; do
    grep foo $i
done

будет работать, так как я думал, что "слишком много файлов" было ограничением оболочки, поэтому оно также не сработало для цикла for.

Сказав это, я всегда позволяю xargs выполнять хрюканную работу по разбиению списка аргументов на управляемые биты таким образом:

find ../path/ | xargs grep foo

Он не запускает процесс для каждого файла, а для группы файлов.

Ответ 5

Ну, у меня были те же проблемы, но мне кажется, что все, что я придумал, уже упоминалось. В основном было две проблемы. Выполнение globs дорого, делает ls на миллион каталоге файлов занимает навсегда (20 + минут на одном из моих серверов), а ls * в каталоге с миллионами файлов занимает навсегда и терпит неудачу с ошибкой "слишком длинный список аргументов".

find /some -type f -exec some command {} \; 

похоже, помогает в обеих проблемах. Кроме того, если вам нужно выполнять более сложные операции над этими файлами, вы можете рассмотреть script свои материалы в несколько потоков. Ниже приведен пример руководства python для работы с CLI-скриптами. http://www.ibm.com/developerworks/aix/library/au-pythocli/?ca=dgr-lnxw06pythonunixtool&S_TACT=105AGX59&S_CMP=GR