Я пытаюсь использовать 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/*.log
to 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
, если ищете самое большое использование диска.