web-dev-qa-db-fra.com

Trouver la taille totale de certains fichiers dans une branche de répertoire

Supposons qu'il existe un répertoire de stockage d'images, par exemple, ./photos/john_doe, dans lequel il existe plusieurs sous-répertoires, où résident de nombreux fichiers (par exemple, *.jpg). Comment puis-je calculer une taille de résumé de ces fichiers sous le john_doe branche?

J'ai essayé du -hs ./photos/john_doe/*/*.jpg, mais cela ne montre que les fichiers individuels. De plus, cela ne suit que le premier niveau d'imbrication du john_doe répertoire, comme john_doe/june/, mais ignore john_doe/june/outrageous/.

Alors, comment pourrais-je parcourir toute la branche, en résumant la taille de certains fichiers?

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

Si plusieurs invocations de du sont nécessaires car la liste de fichiers est très longue, plusieurs totaux seront signalés et devront être additionnés.

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

me donne l'utilisation totale de mon .jpg fichiers dans ce répertoire.

Pour gérer plusieurs répertoires, vous devrez probablement combiner cela avec find d'une manière ou d'une autre.

Vous pourriez trouver exemples de commande utile (il inclut également find)

55
Levon

Principalement, vous avez besoin de deux choses:

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

La réponse ultime est:

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

et une version encore plus rapide, non limitée par la RAM, mais qui nécessite GNU AWK avec support bignum:

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

Cette version présente les fonctionnalités suivantes:

  • toutes les capacités de find pour spécifier les fichiers que vous recherchez
  • prend en charge des millions de fichiers
    • les autres réponses ici sont limitées par la longueur maximale de la liste des arguments
  • ne génère que 3 processus simples avec un débit de tuyau minimal
    • de nombreuses réponses génèrent des processus C + N, où C est une constante et N est le nombre de fichiers
  • ne se soucie pas de la manipulation de chaînes
    • cette version ne fait aucun grepping, ni regexing
    • eh bien, find fait une simple correspondance générique des noms de fichiers
  • formate éventuellement la somme dans une forme lisible par l'homme (par exemple. 5.5K, 176.7M, ...)
    • pour ce faire, ajoutez | numfmt --to=si
19
rindeal

Les réponses données jusqu'à présent ne tiennent pas compte du fait que la liste de fichiers passée de find à du peut être si longue que find divise automatiquement la liste en morceaux, entraînant de multiples occurrences de total.

Vous pouvez soit grep total (locale!) et résumez manuellement, ou utilisez une autre commande. AFAIK, il n'y a que deux façons d'obtenir un grand total (en kilo-octets) de tous les fichiers trouvés par find:
find . -type f -iname '*.jpg' -print0 | xargs -r0 du -a| awk '{sum+=$1} END {print sum}'

Explication
find . -type f -iname '*.jpg' -print0: Trouver tous les fichiers avec l'extension jpg indépendamment de la casse (c.-à-d. * .Jpg, * .JPG, * .Jpg ...) et les sortir (terminés par null).
xargs -r0 du -a: -r: Xargs appellerait la commande même sans aucun argument passé, ce que -r empêche. -0 signifie des chaînes terminées par null (non terminées par une nouvelle ligne).
awk '{sum+=$1} END {print sum}': Récapitule les tailles de fichier générées par la commande précédente

Et pour référence, l'autre façon serait
find . -type f -iname '*.jpg' -print0 | du -c --files0-from=-

10
Jan

Si la liste des fichiers est trop grande, elle ne peut pas être transmise à une seule invocation de du -c, sur un système GNU, vous pouvez faire:

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

(taille exprimée en nombre de blocs de 512 octets). Comme du, il essaie de compter les liens durs une seule fois. Si vous ne vous souciez pas des liens physiques, vous pouvez le simplifier en:

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

Si vous voulez la taille au lieu de l'utilisation du disque, remplacez %b avec %s. La taille sera alors exprimée en octets.

4
Stéphane Chazelas

Les solutions mentionnées jusqu'à présent sont inefficaces (l'exec coûte cher) et nécessitent un travail manuel supplémentaire pour additionner si la liste des fichiers est longue ou si elles ne fonctionnent pas sur Mac OS X. La solution suivante est très rapide, devrait fonctionner sur n'importe quel système, et donne la réponse totale en Go (supprimez a/1024 si vous voulez voir le total en Mo): find . -iname "*.jpg" -ls |Perl -lane '$t += $F[6]; print $t/1024/1024/1024 . " GB"'

2
hobbydad

du parcourt naturellement la hiérarchie des répertoires et awk peut effectuer le filtrage donc quelque chose comme ça peut être suffisant:

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

Cela fonctionne sans GNU.

2
GeoffP

Améliorer la bonne réponse de SHW pour le faire fonctionner avec n'importe quel environnement local, comme Zbyszek l'a déjà souligné dans son commentaire:

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

Un autre serait

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

En supposant que vous recherchez dans un seul répertoire. Si vous voulez regarder le répertoire courant et en dessous

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

C'est ce qui a fonctionné pour moi.

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

Autre alternative utilisant stat plutôt que du

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

Voir la réponse de Gilles sur l'utilisation de **

0
Peter Frost