find -exec с подстановочным знаком

find -exec с подстановочным знаком

Я пытаюсь использовать bash 'find' для обработки всех папок, содержащих файл .log, и получения их размеров. Однако подстановочный знак не работает так, как ожидалось. Это ничего не возвращает:

find . -type d -exec test -e '{}/*.log' \; -exec du -d0 '{}' \;

Однако если я заменю *.logна foo.log, то это будет работать так, как и ожидалось для каталогов, содержащих это имя файла.

Основываясь на некоторых похожих постах SE, я попробовал:

find . -type d -exec bash -c 'test -e "{}/*.log"' \; -exec du -d0 '{}' \;
find . -type d -exec bash -c 'test -e "$1/*.log"' '{}' \; -exec du -d0 '{}' \;

но они не работают лучше.

решение1

При find … -exec test -e '{}/*.log'передаче строки типа something/*.logto test, где *находитсябуквальный. Ни один из инструментов не рассматривает его как подстановочный знак. Некоторые реализации findдаже не будут расширяться, {}если это часть аргумента (в отличие от {}целого аргумента).

Одна из ваших последних попыток встраивается {}в код оболочки.Никогда не встраивайте {}в код оболочки. Другая попытка лучше в этом вопросе, вы близки к решению. Это будеткак быработа:

# still flawed though
find . -type d -exec bash -c 'test -e "$1/"*.log' bash '{}' \; -exec du -d0 '{}' \;

ВидетьКакая вторая буква «ш» в слове sh -c 'some shell code' sh?. Однако главное "исправление" заключается в том, чтобы не заключать в кавычки звездочку в коде оболочки. Таким образом, это подстановочный знак во внутренней оболочке (но не во внешней оболочке, там он правильно заключен в одинарные кавычки). Проблема в том, что *.logможет расшириться до более чем одного слова (если есть много соответствующих файлов), и этот случай нарушит testвызов.

Следующий код найдет каталоги с *.logфайлами:

find . -type d -exec sh -c '
   for f in "$1/"*.log; do test -e "$f" && exit 0; done; exit 1
' sh {} \; -print

Код переносимый. Нет необходимости во внутреннем bash, shдолжно быть быстрее. Замените -printна , -exec du …если хотите.

Это работает, возвращая успех ( exit 0) из внутренней оболочки, как только testподтверждается существование некоторого совпадающего файла¹. Еще не проверенные совпадающие файлы (если таковые имеются) не будут проверяться напрасно, это экономит время. Если совпадений нет, то шаблон останется буквальным, testпотерпит неудачу, и вся оболочка завершит работу с неудачей ( exit 1). Remember -exec— это также тест, поэтому он влияет на то, выполняется ли -print(или -exec du …что-либо еще, что вы туда поместили).


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

find . -name '*.log' … -print

и для анализа его вывода, чтобы изолировать имена каталогов, наконец, для использования xargsс du. Каталоги могут появляться несколько раз, новые строки в именах путей потребуют непереносимого кода (начинающегося с -print0). Я думаю, это было бы неоправданно сложно. Поиск каталогов кажется превосходным.


¹ Примечание test -eсообщает вам, есть ли файлкоторый может быть каталогом или чем-то еще. Для подтверждения существования обычного файла используйте test -f.

решение2

Было бы проще найти/просканировать файлы журналов, а затем собрать уникальные имена каталогов.

Эта findкоманда должна вытащить каталоги, добавив uniqдля удаления дубликатов. Флаги -z/ -0помогают гарантировать, что пути с символами новой строки/пробелов/кавычек будут обработаны безупречно:

find . -type f -name \*.log -exec dirname -z {} \+ | uniq -z | xargs -0 -r du -d0

Добавьте | sort -rn |head, если ищете самое большое использование диска.

Связанный контент