Найдите общий размер определённых файлов в ветке директории.

Вопрос или проблема

Предположим, что есть каталог для хранения изображений, скажем, ./photos/john_doe, в котором есть несколько подкаталогов, где находятся много определенных файлов (например, *.jpg). Как я могу рассчитать общую размерность этих файлов в каталоге john_doe?

Я пробовал du -hs ./photos/john_doe/*/*.jpg, но это показывает только индивидуальные файлы. Также это отслеживает только первый уровень вложенности в каталоге john_doe, как john_doe/june/, но пропускает john_doe/june/outrageous/.

Итак, как я могу обойти весь каталог, суммируя размер определенных файлов?

find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$

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

du -ch public_html/images/*.jpg | grep total
20M total

дает мне общий объем использования моих .jpg файлов в этом каталоге.

Чтобы справиться с несколькими каталогами, вам, вероятно, придется как-то объединить это с find.

Вы можете найти примеры команды du полезными (также включает find)

В первую очередь, вам нужно две вещи:

du -ch -- **/*.jpg | tail -n 1

Если вы ищете эффективный способ суммирования размеров файлов в каталоге, вот окончательный ответ:

find <DIR> -type f -name "*.<EXT>" -printf "%s\n" | gawk -M '{t+=$1}END{print t}'

Если у вас нет GNU AWK с поддержкой больших чисел, используйте эту версию с утилитой bc. Это немного медленнее и ограничено объемом оперативной памяти при подсчете миллиардов файлов.

{ find <DIR> -type f -name "*.<EXT>" -printf "%s+"; echo 0; } | bc

Читаемый размер

Чтобы преобразовать выводимый размер в байтах в читаемый формат, например, 176.7M, просто добавьте:

| numfmt --to=si

Почему это решение выделяется:

  1. Универсальный выбор файлов: Используйте все возможности find, чтобы точно указать, какие файлы вас интересуют.

  2. Работа с большими объемами: Поддерживает миллиарды файлов, в отличие от других решений, ограниченных максимальной длиной списка аргументов.

  3. Эффективное управление процессами: Запускает только 3 простых процесса с минимальной пропускной способностью, в отличие от других методов, которые запускают C+N процессов (где C — это константа, а N — количество файлов).

  4. Без проблем с манипуляцией строками: Этот подход избегает ненужной манипуляции строками, grep или regex. Команда find справляется со всем, что вам когда-либо потребуется, нативно и надежно.

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

Вы можете либо grep total (локаль!) и суммировать вручную, либо использовать другую команду. Насколько я знаю, есть только два способа получить общий итог (в килобайтах) всех файлов, найденных с помощью find:
find . -type f -iname '*.jpg' -print0 | xargs -r0 du -a| awk '{sum+=$1} END {print sum}'

Объяснение
find . -type f -iname '*.jpg' -print0: Найти все файлы с расширением jpg независимо от регистра (т.е. *.jpg, *.JPG, *.Jpg…) и вывести их (разделенные нулем).
xargs -r0 du -a:
-r: Xargs выполнит команду даже без переданных аргументов, что предотвращается с помощью -r. -0 означает нулевое завершение строк (не окончание новой строкой).
awk '{sum+=$1} END {print sum}': Суммирует размеры файлов, выведенные предыдущей командой.

А для справки, другой способ будет
find . -type f -iname '*.jpg' -print0 | du -c --files0-from=-

Если список файлов слишком велик, чтобы его можно было передать в один вызов du -c, на системе GNU вы можете сделать следующее:

find . -iname '*.jpg' -type f -printf '%b\t%D:%i\n' |
  sort -u | cut -f1 | paste -sd+ - | bc

(размер выражается в количествах блоков по 512 байт). Как du, он пытается посчитать жесткие ссылки только один раз. Если вам не важны жесткие ссылки, вы можете упростить это:

(printf 0; find . -iname '*.jpg' -type f -printf +%b) | bc

Если вы хотите получить размер вместо использования диска, замените %b на %s. Размер будет выражен в байтах.

Упомянутые до сих пор решения неэффективны (exec дорог), а также требуют дополнительной ручной работы для суммирования, если список файлов длинный, или они не работают на Mac OS X. Следующее решение очень быстрое, должно работать на любой системе и дает общий ответ в ГБ (удалите /1024, если хотите увидеть общее в МБ):

find . -iname "*.jpg" -ls |perl -lane '$t += $F[6]; print $t/1024/1024/1024 . " GB"'

Улучшение отличного ответа SHW, чтобы он работал с любым языком, как уже упоминал Збысек в своем комментарии:

LC_ALL=C find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$

du естественно проходит по иерархии каталогов, а awk может выполнять фильтрацию, поэтому что-то вроде этого может быть достаточным:

du -ak | awk 'BEGIN {sum=0} /\.jpg$/ {sum+=$1} END {print sum}'

Это работает без GNU.

Вот что сработало для меня.

find -type f -iname *.jpg -print0 | du -ch --files0-from=- | grep total$

Используя современный fd (также известный как fd-find или fdfind на Ubuntu)

fdfind -e jpg -X du -ch | tail -1

Мне показалось, что fd проще в использовании, чем find, и нет необходимости включать globstar

Трюк заключается в использовании заглавной X –exec-batch, которая выполняет команду только один раз, а не строчной x, которая выполняет обычный exec для каждого файла.

Чтобы установить на Ubuntu:

sudo apt install fd-find

Смотрите больше

Другой вариант был бы

ls -al <directory> | awk '{t+=$5}END{print t}}'

Предполагая, что вы смотрите в одном каталоге. Если вы хотите посмотреть в текущем каталоге и ниже:

ls -Ral <directory> | awk '{t+=$5}END{print t}}'

Другой альтернативный вариант — использовать stat вместо du

stat -L -c %s ** | awk '{s+=$1} END {printf "%.0f\n", s}'

Смотрите ответ Жиля о использовании **

Это смешение нескольких ответов и комментариев, которые делают то, что мне нужно.

find . \( -iname "*.jpg" -o -iname "*.png" \) -type f -exec du -bc {} + | grep total$ | cut -f1 | awk '{ total += $1 }; END { print total }'| numfmt --to=iec

  • find найдет все файлы рекурсивно
  • -iname используется для нечувствительности к регистру
  • -o и круглые скобки для поиска по нескольким паттернам
  • du -bc получит размер файлов, иногда с более чем одним вызовом, если файлов много
  • grep total выведет только строку total, как указано в du
  • cut -f1 возьмет только фактические целые значения
  • awk суммирует их все
  • numfmt преобразует его в читаемый формат

Ответ или решение

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

Полное решение задачи:

  1. Использование команды find с du для суммирования файлов:
    Вы можете воспользоваться следующей командой:

    find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$

    Эта команда находит все файлы с расширением .jpg в директории john_doe и всех её подкаталогах и передаёт их в du, который суммирует размеры файлов. grep total$ фильтрует вывод, оставляя только строку с итоговым размером. Однако стоит учитывать, что если количество файлов будет очень большим, возможно, придется выполнить несколько вызовов du, что может привести к множественным выводам.

  2. Альтернативное решение с awk или bc:
    Если вы хотите избежать проблемы с несколькими вызовами du, можно воспользоваться следующим способом:

    find ./photos/john_doe -type f -name '*.jpg' -print0 | du -ch --files0-from=- | grep total$

    В этом случае используется -print0 для вывода списка файлов с нулями (\0) в качестве разделителей. Это позволяет избежать проблем с пробелами в именах файлов.

  3. Посчитать размер в байтах:
    Если вы хотите получить общий размер в байтах и преобразовать его в удобочитаемый формат, используйте awk:

    find ./photos/john_doe -type f -name '*.jpg' -printf "%s\n" | awk '{total += $1} END {print total, "bytes"}'

    Эта команда находит все файлы с расширением .jpg, выводит их размер в байтах, и с помощью awk суммирует их размеры.

  4. Для вывода в удобочитаемом формате:
    Чтобы вывести общий размер в удобочитаемом формате (например, МБ или ГБ), можно добавить numfmt:

    find ./photos/john_doe -type f -name '*.jpg' -printf "%s\n" | awk '{total += $1} END {print total}' | numfmt --to=iec

Заключение

Вышеуказанные команды обеспечивают эффективный способ подсчета общего размера определённых файлов в каталоге и всех его подкаталогах. Каждый метод имеет свои преимущества, и выбор зависит от ваших предпочтений и требований к удобочитаемости. Убедитесь, что все команды выполняются в терминале Unix-подобной системы, где установлен необходимый набор утилит.

Оцените материал
Добавить комментарий

Капча загружается...