Объедините find, grep и xargs с printf - PullRequest
0 голосов
/ 21 февраля 2020

У меня есть команда поиска в сочетании с exe c grep и параметром printf:

find  -L /home/blast/dirtest -maxdepth 3  **-exec grep -q  "pattern" {} \;**  -printf '%y/#/%TY-%Tm-%Td %TX/#/%s/#/%f/#/%l/#/%h\n' 2> /dev/null

Результат:

f/#/2018-01-01 10:00:00/#/191/#/filee.xml/#//#//home/blast/dirtest/01/05

Мне нужен printf, чтобы получить все нужные файлы информация сразу (дата, размер шрифта и т. д. c)

Приведенная выше команда работает нормально. Но опция exe c слишком медленная по сравнению с xargs.

Я пытался сделать то же самое с xarg, но мне это не удалось. Любая идея о том, как добиться этого? используя команду xargs, сохраняя желаемый printf или аналогичный.

Спасибо

Ответы [ 3 ]

3 голосов
/ 24 февраля 2020

Ваш код:

find  -L /home/blast/dirtest -maxdepth 3 \
    -exec grep -q  "pattern" {} \; \
    -printf '%y/#/%TY-%Tm-%Td %TX/#/%s/#/%f/#/%l/#/%h\n' 2> /dev/null

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

Если вы используете утилиты GNU, вы можете уменьшить количество grep обрабатывает что-то вроде:

(
    format=\''%y/#/%TY-%Tm-%Td %TX/#/%s/#/%f/#/%l/#/%h\n'\'

    find -L /home/blast/dirtest -maxdepth 3 -print0 |\
    xargs -0 grep -l -Z "pattern" |\
    xargs -0 sh -c 'find "$@" -printf '"$format" --
) 2>/dev/null
  • для ясности, сохраняйте форматную строку в переменной
  • , используйте -print0 / -0 / -Z опции для включения с нулевым разделителем data
  • создать начальный список файлов с find
  • фильтром "pattern" с grep (использование xargs минимизирует количество вызовов grep)
  • передать отфильтрованный список файлов в другой xargs, чтобы запустить минимальное число find -printf
  • в секунду xargs, вызвать подоболочку, чтобы можно было добавить дополнительные аргументы (find требует пути к предшествуйте операторам)
  • фиктивный второй аргумент (--) для вызова sh -c предотвращает потерю первого имени файла из-за присваивания $0
1 голос
/ 23 февраля 2020

Чтобы сделать это именно так, как вы хотите:

find  -L /home/blast/dirtest/ -maxdepth 3 \
    -printf '%p@%y/#/%TY-%Tm-%Td %TX/#/%s/#/%f/#/%l/#/%h\n' \
    > tmp.out
cut -d@ -f1 tmp.out \
    | xargs grep -l "pattern" 2>/dev/null \
    | sed 's/^/^/; s/$/@/' \
    | grep -f /dev/stdin tmp.out \
    | sed 's/^.*@//'

Это работает при условии, что у вас нет символов @ в именах файлов.

То, что он делает, это избежать Сначала выполните grep и просто выведите все файлы с запрошенными метаданными во временный файл.

Но в каждой строке также указывается полный путь (%p@).

Затем мы извлекаем ( cut) полные пути из этого списка и список файлов, которые содержат шаблон (xargs grep).

Затем мы используем sed, чтобы префиксить каждое такое имя файла с ^ и добавить к нему суффикс с @, что делает его шаблоном в нашем файле tmp.out.

Затем мы используем этот шаблон (grep -f /dev/stdin), чтобы извлечь только те пути из большого списка в tmp.out.

Теперь все, что осталось, это удалить искусственный полный путь, к которому мы добавили префикс, с помощью последней команды sed.

Видя, как вы использовали /home, есть большая вероятность, что вы используете Linux , который, если вы готовы принять некоторые изменения формата вывода, позволяет вам o это несколько элегантнее:

find -L /home/blast/dirtest/ -maxdepth 3 \
    | xargs grep -l "pattern" 2>/dev/null \
    | xargs stat --printf '%F/#/%y/#/%s/#/%n\n'

Вывод stat --printf отличается от find -printf (и от MacOS 'stat -f), но это та же информация.

Заметьте, однако, что, поскольку вы передали -L для поиска, и вы получаете результат:

  1. Результаты ограничены типами файлов, которые можно подбирать, поэтому они будут никогда не быть каталогами, ссылками и т. д. c ..
  2. Если вы наткнетесь на неработающую ссылку, она не будет в выводе, потому что она не может быть найдена.
0 голосов
/ 24 февраля 2020

Я нашел интересную вещь о опции -exe c. Мы могли бы запустить grep один раз, используя exe c со знаком плюс (+)

-exec command {} +
              This variant of the -exec option runs the specified command on the selected files, but the command line is built by appending each selected file name at the end; the  total
              number  of  invocations  of  the  command  will be much less than the number of matched files.  The command line is built in much the same way that xargs builds its command
              lines.  Only one instance of ’{}’ is allowed within the command.  The command is executed in the starting directory.

Это означает, что если я изменю это:

-exec grep -l 'pattern'  {} \;

этим (замените точка с запятой со знаком плюс):

-exec grep -l 'pattern'  {} \+

Значительно улучшит производительность.

Тогда я могу передать только один xargs только для форматной печати. ​​

...