Comment trouver des fichiers et totaliser leur taille?

12

Je voudrais trouver une série de fichiers (basés sur une expression générique) et totaliser leur utilisation du disque.

Quelque chose comme ça:

$ find . -name 'flibble*' -ctime +90 -exec du -sh {} \;

2.1G    ./flibble_116.log
2.1G    ./flibble_83.log
2.1G    ./flibble_211040_157.log
2.1G    ./flibble3747_51.log

Ce travail. Mais cela ne produit pas le résultat que je recherche. Il répertorie l'espace utilisé par chaque fichier, tout comme findson itération.

Ce que je veux, c'est le total dude tous les fichiers trouvés.

Paul
la source

Réponses:

12

Solution

En fournissant l'option -c(ou --total) à du(1), vous pouvez lui demander de produire un grand total. Si votre implémentation du(1)prend en charge l'une de ces options, vous pouvez obtenir l'effet souhaité à l'aide de la commande suivante:

$ find . -name 'flibble*' -ctime +90 -exec du -shc {} +

EDIT: Notez que si le nombre de fichiers dépasse le nombre maximum de paramètres autorisés par votre système, il findpeut toujours s'exécuter commandplusieurs fois. Certaines implémentations de du(1)prennent également en charge la lecture des noms de fichiers à partir d'un fichier, ce qui ne souffre pas de la limitation mentionnée:

$ find -name 'flibble*' -ctime +90 -print0 > filenames
$ du -shc --files0-from=filenames

Explication

La différence entre la sémantique de -exec command {} \;et -exec command {} +est la suivante:

  • command {} \;s'exécute commandune fois pour chaque résultat de find. Le chemin d'accès du résultat est transmis à la place de {}.

    $ touch 1 2 3
    $ find  1 2 3 -maxdepth 0 -exec echo {} \;
    1
    2
    3
  • command {} +s'exécute command, lorsque tous les résultats ont été récupérés. Les chemins d'accès des résultats sont passés à la place de {}.

    $ touch 1 2 3
    $ find  1 2 3 -maxdepth 0 -exec echo {} +
    1 2 3

L' -print0option entraîne l' find(1)impression des noms de fichiers trouvés sur la sortie standard, séparés par le caractère nul, et l' --files0-fromoption provoque la du(1)lecture des noms de fichiers séparés par des valeurs nulles. Contrairement au nouveau caractère de ligne, le caractère nul peut ne pas apparaître dans un nom de fichier, la sortie est donc sans ambiguïté.

Pour en savoir plus sur les options de du(1)et find(1), vous devez consulter les pages de manuel respectives:

$ man du
$ man find
Witiko
la source
2
Vous pouvez vous retrouver avec plusieurs totaux si le nombre de fichiers est important (1K +) en raison de la limitation du nombre d'arguments de ligne de commande.
ychaouche
Je peux confirmer @ychaouche, j'ai eu le problème en essayant d'évaluer la taille de plus de 30k fichiers.
Adrien H
Si c'est un problème, certaines implémentations de du(1)prennent également en charge la lecture des noms de fichiers à partir d' un fichier: find 1 2 3 -maxdepth 0 -print0 > filenames; du -shc --files0-from=filenames.
Witiko
4

Essaye ça:

du -c `find . -name 'flibble*' -ctime +90` | tail -1

La commande d'origine donne un argument, puis l'exécute, jusqu'à ce qu'elle passe par tous les arguments. De cette façon, vous lui donnez simplement tous les arguments à la fois, puis vous coupez les tailles séparées et ne laissez que le total. Vous pouvez supprimer le tuyau et la queue pour afficher la taille de chaque fichier si vous le souhaitez.

Andre S.
la source
Cela ne produira pas de résultats corrects avec les noms de chemin contenant des espaces. La bonne façon de procéder consiste à utiliser l' -exec du -c {} +option de find, qui transmettra les noms de chemin sans modification à du.
Witiko
4

Vous pouvez essayer ceci:

find . -name 'flibble*' -ctime +90 -exec du -ch {} + | grep total
skush
la source
2

Je voudrais findlui - même imprimer la taille et utiliser un autre outil pour calculer le total:

find . -name 'flibble*' -ctime +90 -printf "%s\n" |
perl -lnE '$sum += $_} END {say $sum'

Si vous souhaitez également voir les noms de fichiers:

find . -name 'flibble*' -ctime +90 -printf "%s\t%p\n" |
perl -apE '$sum += $F[0]} END {say $sum'
glenn jackman
la source
1

Un liner qui devrait fonctionner pour obtenir un total de gigaoctets sur la plupart des systèmes:

echo "$(( ($(find . -name 'flibble*' -ctime +90 -type f -printf '%k+' )0)/1024/1024 )) GB"
Robert Boyd
la source