Знайдіть загальний розмір певних файлів у відділенні каталогу


140

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

Я спробував du -hs ./photos/john_doe/*/*.jpg, але це показує лише окремі файли. Крім того, це відслідковує лише перший рівень гнізда john_doeкаталогу, як john_doe/june/, але пропускає john_doe/june/outrageous/.

Отже, як я міг пройти всю гілку, підсумовуючи розмір певних файлів?

Відповіді:


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

Якщо duпотрібне більше одного виклику , оскільки список файлів дуже довгий, буде повідомлено про декілька підсумків та їх потрібно підсумувати.


7
знайти -iname 'файл *' -exec du -cb {} + | греп загальна $ | вирізати -f1 | вставити -sd + - | bc # підсумований розмір байтів
Michal Čizmazia

3
Якщо ваша система працює на іншій мові, тоді вам потрібно змінити загальну суму $ на інше слово, наприклад, razem $ польською мовою.
Zbyszek

1
Ви можете додати LC_ALL=POSIXяк префікс завжди grep для всього, як це:LC_ALL=POSIX find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$
Sven

2
Якщо ви не використовуєте -name, то змініть grep на grep -P "\ttotal$"або інакше, він також захопить усі файли, що закінчуються на "total".
thoan

3
@ MichalČizmazia деякі оболонки (наприклад, Git Bash для Windows) не мають bc, тому ось більш портативне рішення:find -name '*.jpg' -type f -exec du -bc {} + | grep total$ | cut -f1 | awk '{ total += $1 }; END { print total }'
thoan

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

дає мені загальне використання моїх .jpgфайлів у цьому каталозі.

Щоб мати справу з кількома каталогами, вам, мабуть, доведеться findякось комбінувати це .

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


2
Це не проходить основні каталоги?
mbaitoff

Це легше набрати, ніж прийняте рішення, але лише наполовину праворуч, воно не буде містити зображення у підкаталогах. Добре знати, чи всі файли в одному каталозі.
gbmhunter

@gbmhunter Я думаю, що якщо ви додасте параметр -R до -ch, ви також отримаєте підкаталоги, оскільки він рекурсивно перетинає дерево каталогів. Я зараз не за комп’ютером, щоб спробувати це, хоч для підтвердження.
Левон

1
Я не бачу -Rопції на man7.org/linux/man-pages/man1/du.1.html . І я не думаю, що рекурсивний варіант допоможе в цьому випадку, оскільки оболонка робить глобальне розширення перед передачею аргументів du.
gbmhunter

22

Перш за все, вам потрібно дві речі:

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

дуже хороша відповідь. Простіше, ніж використання пошуку (доки * або ** відповідає структурі каталогів)
Андре де Міранда,

Він також може обробляти дуже довгі списки файлів, тоді як використання findможе повернути помилкові результати.
Ерік Фурні

розширення брекет-підтяжки дозволяє також вимірювати кілька наборів підстановок. du -ch -- ./{dir1,dir2}/*.jpgабоdu -ch -- ./{prefix1*,prefix2*}.jpg
Дж.Моней

@EricFournie Однак я отримав Argument list too longпомилку під час обробки близько 300k текстових файлів.
xtluo

Максимальну кількість аргументів для команди (у цьому випадку імена файлів, повернені в результаті розширення підстановки), можна перевірити за допомогою getconf ARG_MAX. Якщо у вас є більше, вам потрібно буде обробити файли один за одним або послідовно за допомогою циклу for.
Ерік Фурні

17

Кінцева відповідь:

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

і навіть більш швидка версія, не обмежена оперативною пам’яттю, але для цього потрібен GNU AWK з підтримкою bignum:

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

Ця версія має такі функції:

  • всі можливості findвказувати потрібні файли
  • підтримує мільйони файлів
    • інші відповіді тут обмежені максимальною довжиною списку аргументів
  • породжує лише 3 прості процеси з мінімальною пропускною здатністю
    • тут багато відповідей породжують процеси C + N, де C - деяка константа, а N - кількість файлів
  • не турбується з обробкою струнами
    • ця версія не робить жодного зіпсування або повторного наведення
    • добре, findчи просте підстановлення підстановок з іменами файлів
  • необов'язково форматує суму в легкий для читання вигляд (наприклад. 5.5K, 176.7M...)
    • зробити це додаток | numfmt --to=si

Мені подобається простота цієї відповіді, хоча вона працювала для мене лише тоді, коли я вводив пробіли після вступної дужки та перед фіксацією. Мені цікаво, чи дійсно він підтримуватиме "infiinte" кількість файлів, хоча :)
andyb

1
@andyb дякую за відгук, пробіли навколо брекетів дійсно потрібні в BASH, я використовую ZSH, тому я цього не помічав. А кількість файлів обмежена доступною оперативною пам’яттю у вашій системі, оскільки використання пам’яті bc повільно зростає в міру надходження чисел.
Ян Чрен - rindeal

8

Надані досі відповіді не враховують, що список файлів, переданий від знаходження до ду, може бути настільки довгим, що пошук автоматично розбиває список на шматки, внаслідок чого виникає кілька випадків total.

Можна або grep total(локально!) І підсумовувати підсумки вручну, або використовувати іншу команду. AFAIK є лише два способи отримати загальну суму (у кілобайтах) усіх файлів, знайдених пошуку:
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=-


Додатковий натяк: На моєму жорсткому диску з 23428 файлами (22323 - зображення) перший метод працює 1 сек, а другий - 3,8 сек.
січня

Зауважте, що обидва припускають систему GNU. Перший передбачає, що імена файлів не містять символів нового рядка.
Стефан Шазелас

Б'юсь у заклад, що на це du --file0-fromпішло більше часу, оскільки ви запустили його першим (ефект кешування).
Стефан Шазелас

З xargs, du -aможе бути запущено декілька , тож у вас можуть виникнути розбіжності, якщо є жорсткі посилання.
Стефан Шазелас

3

Якщо список файлів занадто великий, що його неможливо передати одному виклику 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. Розмір буде виражений у байтах.


-bash: bc: command not foundCentos - Linux 2.6.32-431.el6.x86_64
yeya

@yeya, це здається, що розгортання вашого CentOS порушено. bc- необов'язкова команда POSIX.
Стефан Шазелас

1

Раніше згадані рішення неефективні (exec коштує дорого) і потребують додаткової ручної роботи, щоб підсумовувати, якщо список файлів довгий або вони не працюють на Mac OS X. Наступне рішення дуже швидко, має працювати в будь-якій системі та дає загальну відповідь у ГБ (видаліть / 1024, якщо ви хочете побачити загальну суму в МБ): find . -iname "*.jpg" -ls |perl -lane '$t += $F[6]; print $t/1024/1024/1024 . " GB"'


Ні вони -inameне -lsє стандартними / портативними, тому він також не працюватиме в будь-якій системі . Він також не працюватиме належним чином, якщо є назви файлів або цілі символьних посилань, які містять символи нового рядка.
Стефан Шазелас

Також зауважте, що він дає суму розмірів файлів, а не їх використання на диску. Для символьних посилань він дає розмір символьних посилань, а не файли, на які вони вказують.
Стефан Шазелас

1

Покращення чудової відповіді SHW, щоб вона працювала з будь-якою локальною службою, як уже зазначив Збишек у своєму коментарі:

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

1

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

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

Це працює без GNU.


1
Це дорожче, оскільки тягне за собою statвиклик файлів, які не відповідають шуканому шаблону.
Закон29

Тільки це рішення працює на моєму комп'ютері.
Маттіас М
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.