Comment obtenir la taille réelle du répertoire (hors du)?

17

Comment obtenir la taille réelle du répertoire à l'aide des outils standard UNIX / Linux?

Question alternative: Comment puis-je obtenir du pour me montrer la taille réelle du répertoire (pas l'utilisation du disque)?

Puisque les gens semblent avoir des définitions différentes du terme "taille": Ma définition de "taille de répertoire" est la somme de tous les fichiers réguliers dans ce répertoire.

Je ne me soucie PAS de la taille de l'inode du répertoire ou quoi que ce soit (blocs * taille de bloc) que les fichiers occupent sur le système de fichiers respectif. Un répertoire avec 3 fichiers, 1 octet chacun, a une taille de répertoire de 3 octets (selon ma définition).

Le calcul de la taille du répertoire à l'aide de du semble peu fiable.
Par exemple, mkdir foo && du -b foosignale "4096 foo", 4096 octets au lieu de 0 octet. Avec de très gros répertoires, la taille du répertoire signalée par du -hspeut être réduite de 100 Go (!) Et plus (système de fichiers compressé).

Alors, quel (outil / option) doit être utilisé pour obtenir la taille réelle du répertoire?

basic6
la source
Quel système de fichiers est utilisé dans le nouvel emplacement - est-ce xfspar hasard?
Sergey Vlasov
Et si votre nouveau FS est vraiment XFS, l'utilisation considérablement accrue du disque est probablement due à une préallocation agressive , qui diminue la fragmentation des fichiers au détriment de l'utilisation du disque.
Sergey Vlasov

Réponses:

8

Voici un script affichant une taille de répertoire lisible par l'homme à l'aide des outils standard Unix (POSIX).

#!/bin/sh
find ${1:-.} -type f -exec ls -lnq {} \+ | awk '
BEGIN {sum=0} # initialization for clarity and safety
function pp() {
  u="+Ki+Mi+Gi+Ti+Pi+Ei";
  split(u,unit,"+");
  v=sum;
  for(i=1;i<7;i++) {
    if(v<1024) break;
    v/=1024;
  }
  printf("%.3f %sB\n", v, unit[i]);
}
{sum+=$5}
END{pp()}'

par exemple:

$ ds ~        
72.891 GiB
jlliagre
la source
Et maintenant , je trouve une autre option qui manque dans toutes proposées lsinvocations ici: -q. Sans cette option, le script se brisera si un nom de fichier contient des caractères de nouvelle ligne. Écrire des scripts shell vraiment fiables est trop difficile…
Sergey Vlasov
@SergeyVlasov Le script que j'ai publié ne doit pas rompre avec de tels fichiers, il ne fait qu'ignorer les lignes supplémentaires. Le seul problème se produirait si un fichier soigneusement conçu avait une ligne supplémentaire avec un cinquième deux-points qui contient une valeur numérique. Votre suggestion éviterait en effet cette situation. Merci pour l'astuce, le script a été mis à jour.
jlliagre
Excellente réponse. +1 à vous monsieur
ehime
C'est l'une des solutions les plus fiables. Il fonctionne avec des noms de fichiers contenant des espaces ou des guillemets et imprime une taille lisible par l'homme.
basic6
@KIAaze Merci d'avoir révisé et corrigé mon code!
jlliagre
8

Certaines versions de duprennent en charge l'argument --apparent-sizepour afficher la taille apparente au lieu de l'utilisation du disque. Votre commande serait donc:

du -hs --apparent-size

À partir des pages de manuel pour du incluses avec Ubuntu 12.04 LTS:

--apparent-size
      print apparent sizes,  rather  than  disk  usage;  although  the
      apparent  size is usually smaller, it may be larger due to holes
      in (`sparse') files, internal  fragmentation,  indirect  blocks,
      and the like
Brian
la source
1
ne fonctionne pas: signalez un espace pour les répertoires vides
Karl Forner
1
cela a fonctionné pour moi.
connorbode
2
Il donne des tailles considérablement différentes lorsque vous comparez des répertoires sur différents systèmes de fichiers. Par exemple, le même dossier a une taille apparente de 290 Go sur le système de fichiers zfs et 324 Go d'exFat. Les solutions ci-dessus donnent la même taille.
Pixus.ru
4

Juste une alternative, en utilisant ls:

ls -nR | grep -v '^d' | awk '{total += $5} END {print total, "Total"}'

ls -nR: -ncomme -l, mais liste les UID et GID numériques et -R répertorie les sous-répertoires de manière récursive.

grep -v:Inversez le sens de l'appariement pour sélectionner des lignes non appariées. (-v est spécifié par POSIX.).'^ d'exclura les répertoires.

Commande Ls: http://linux.about.com/od/commands/l/blcmdl1_ls.htm

Man Grep: http://linux.die.net/man/1/grep

ÉDITER :

Édité comme suggestion @ Sergey Vlasov.

stderr
la source
L'utilisation de l' -noption pour lsau lieu de -l(afficher les numéros UID / GID au lieu des noms) est plus sûre, car les noms d'utilisateur et de groupe peuvent contenir des espaces (par exemple, si winbindou sssdest utilisé pour joindre le système à un domaine Windows, vous pouvez obtenir des noms de groupe comme domain users) . Il devrait également être plus rapide car il n'est pas nécessaire de rechercher les noms d'utilisateurs et de groupes.
Sergey Vlasov
Merci, c'est beaucoup plus rapide que find -exec ls!
gpothier
4

En supposant que vous avez dude GNU coreutils, cette commande devrait calculer la taille apparente totale du nombre arbitraire de fichiers normaux dans un répertoire sans aucune limite arbitraire sur le nombre de fichiers:

find . -type f -print0 | du -scb --files0-from=- | tail -n 1

Ajoutez l' -loption dus'il y a des fichiers liés en dur et que vous souhaitez compter chaque lien en dur séparément (par défautdu compte plusieurs liens durs qu'une seule fois).

La différence la plus importante avec plain du -sbest que récursif ducompte également les tailles de répertoires, qui sont rapportées différemment par les différents systèmes de fichiers; pour éviter cela, la findcommande est utilisée pour transmettre uniquement les fichiers normaux à du. Une autre différence est que les liens symboliques sont ignorés (s'ils doivent être comptés, la findcommande doit être ajustée).

Cette commande consommera également plus de mémoire que plain du -sb, car l'utilisation des --files0-from=FILEmarques de dupériphérique de stockage et d'inode de tous les dossiers traités, par opposition au comportement par défaut de se rappeler que les fichiers avec plus d'un lien dur. (Ce n'est pas un problème si l' -loption est utilisée pour compter plusieurs fois les liens durs, car la seule raison de stocker les numéros de périphérique et d'inode est d'ignorer les fichiers liés durement qui avaient déjà été traités.)

Si vous souhaitez obtenir une représentation lisible par l'homme de la taille totale, ajoutez simplement l' -hoption (cela fonctionne car elle dun'est invoquée qu'une seule fois et calcule la taille totale elle-même, contrairement à d'autres réponses suggérées):

find . -type f -print0 | du -scbh --files0-from=- | tail -n 1

ou (si vous craignez que certains effets de -bsoient ensuite remplacés par -h)

find . -type f -print0 | du -sc --apparent-size -h --files0-from=- | tail -n 1
Sergey Vlasov
la source
Je ne sais pas quoi faire pour FreeBSD - bien qu'il -bpuisse probablement être remplacé par -A -B 1, il n'y a pas d'équivalent pour --files0-from=-, et l'utilisation xargsnécessitera quelques solutions de contournement au cas où la liste des fichiers serait plus grande que ARG_MAX(et une solution externe pour une sortie lisible par l'homme).
Sergey Vlasov
3

Si tout ce que vous voulez est la taille des fichiers, à l'exclusion de l'espace occupé par les répertoires, vous pouvez faire quelque chose comme

find . -type f -print0 | xargs -0 du -scb | tail -n 1

@SergeyVlasov a souligné que cela échouera si vous avez plus de fichiers que argmax. Pour éviter cela, vous pouvez utiliser quelque chose comme:

find . -type f -exec du -sb '{}' \; | gawk '{k+=$1}END{print k}'
terdon
la source
1
Cette commande donnera silencieusement un résultat erroné si le répertoire contient tellement de fichiers qu'ils ne tiennent pas dans la limite de la taille des arguments execve () - dans ce cas xargs, invoquera duplusieurs fois, et chaque invocation affichera le grand total juste pour sa part de la liste complète des fichiers, tailaffichera alors uniquement la taille totale de la dernière partie.
Sergey Vlasov
1
@SergeyVlasov bon point, je n'y avais pas pensé, merci, réponse mise à jour.
terdon