4

Я пытаюсь найти во многих XML-файлах определенные строки, но не другие строки, и у меня возникают проблемы при составлении команды для этого. Я только хочу перечислить имена файлов, которые соответствуют критериям включения / исключения. Я пытался:

find . -name *.xml -exec grep -li "string1\|string2" {} \; | xargs grep -Li "string3\|string4"

Но у меня возникли проблемы, потому что имена файлов, которые возвращаются из find, имеют пробелы в именах, а второй grep разбивает их на маленькие кусочки и, конечно, не находит такие файлы. Я попытался добавить -0 к xargs, и он удаляет ошибки, но он говорит "Имя файла слишком длинное" и выполняет только первый grep.

Как настроить эту команду, чтобы она правильно работала с файлами с пробелами в именах?

4 ответа4

3

Вы можете сделать все это в одной find которая позволяет избежать всех проблем с пробелами в именах файлов. Что-то вроде

find . -exec grep -liq "string1\|string2" {} \; -not -exec grep -liq "string3\|string4" {} \; -print

«-Q» подавляет весь вывод grep. Первичный -exec возвращает true, когда процесс завершает работу с состоянием 0, как это делает grep, когда находит совпадение, а первичный -not первичный отменяет это. Таким образом, мы непосредственно накладываем два условия на find , и в результате мы печатаем только те имена файлов, которые удовлетворяют обоим - не требуется конвейер!

3

Есть несколько способов сделать это. Это должно сводить к минимуму общее количество процессов:

find . -name \*.xml -print0          \   # List of *.xml files (NUL-terminated)
  | xargs -0 grep -Zli 'string[12]'  \   # is input to first grep, which sends (NUL-term'd)
  | xargs -0 grep -Li  'string[34]'      # file list to second grep

Спасибо Мэтту Гибсону за напоминание нам о флаге -Z GNU grep.

2

Как упоминалось в моем комментарии, я думаю, что все, что вы пропустили, это флаг -Z на первом grep который идет вместе с -0, который вы пытались применить к своим xargs:

find . -name "*.xml" -exec grep -liZ "string1\|string2" {} \; | xargs -0 grep -Li "string3\|string4"
0

Если ограничивающим фактором является ЦП (т. Е. Ваш диск работает быстро) и у вас больше ядер ЦП, вы можете использовать GNU Parallel:

find . -type f| parallel grep -Lq foo {} '||' grep -l bar {}

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

Посмотрите вступительное видео, чтобы узнать больше: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .