Как вы справляетесь с проблемой "Слишком много файлов" при работе в 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