Comment `du` uniquement l'espace utilisé par des fichiers qui ne sont pas liés par un lien fixe ailleurs?

14

En utilisant rsync --link-destdes instantanés peu encombrants , comment savoir combien d'espace j'ai réellement économisé? Ou plus général:

Comment savoir combien d'espace un répertoire utilise en considérant uniquement les fichiers qui ne sont pas liés par un lien dur ailleurs en dehors de la structure du répertoire? Question différente: combien d'espace serait réellement libéré après la suppression de ce répertoire? ( du -hsmentir. L'espace requis pour les liens physiques eux-mêmes peut être inclus)

Tobias Kienzler
la source
2
Par défaut, GNU dune compte les tailles de fichier qu'une seule fois, même si elles sont liées de manière fixe, sauf si vous utilisez l' option -l/ --count-links. Vous exécutez dudeux fois sur l'arborescence entière, avec et sans cette option et la différence entre les tailles doit être la quantité d'espace que vous avez économisée sur tous les répertoires.
jw013

Réponses:

9

En supposant qu'il n'y a pas de liens physiques internes (c'est-à-dire que chaque fichier avec plus d'un lien physique est lié depuis l'extérieur de l'arborescence), vous pouvez faire:

find . -links -2 -print0 | du -c --files0-from=-

EDIT Et voici ce que j'ai esquissé dans le commentaire, appliqué. Seulement sans du; bravo à @StephaneChazelas pour avoir remarqué qu'il dun'est pas nécessaire. Explication à la fin.

( find . -type d -printf '%k + ' ; \
  find . \! -type d -printf '%n\t%i\t%k\n' | \
    sort | uniq -c                         | \
    awk '$1 >= $2 { print $4 " +\\" }' ; \
  echo 0 ) | bc

Ce que nous faisons est de créer une chaîne avec l'utilisation du disque (en Ko) de chaque fichier pertinent, séparée par des signes plus. Ensuite, nous alimentons ce gros ajout à bc.

La première findinvocation fait cela pour les répertoires.

Le second findimprime le nombre de liens, l'inode et l'utilisation du disque. Nous passons cette liste sort | uniq -cpour obtenir une liste de (nombre d'apparitions dans l'arborescence, nombre de liens, inode, utilisation du disque).

Nous passons cette liste à travers awk, et, si le premier champ (# d'apparences) est supérieur ou égal au second (# de liens physiques), ce qui signifie qu'il n'y a pas de liens vers ce fichier depuis l'extérieur de l'arborescence, alors imprimez le quatrième champ ( utilisation du disque) avec un signe plus et une barre oblique inversée.

Enfin, nous sortons a 0, donc la formule est syntaxiquement correcte (elle le ferait dans le +cas contraire) et la transmettons à bc. Phew.

(Mais j'utiliserais la première méthode la plus simple, si elle donne une bonne réponse.)

angus
la source
Merci, oui si cette condition est remplie, cela fonctionne. Et si ce n'est pas le cas?
Tobias Kienzler
Cela ne fonctionne pas car cela ne tient pas compte de la taille des répertoires eux-mêmes (qui ont généralement au moins 2 liens, et si ce n'était pas le cas, les fichiers seraient comptés deux fois).
Stéphane Chazelas
1
Ensuite, il serait nécessaire d'utiliser findpour imprimer une liste de tous les fichiers avec leurs inodes et le nombre de liens; puis une combinaison de sort | uniq -cpour obtenir le nombre de fois que chaque inode apparaît dans l'arborescence, puis filtrer ceux dont le nombre de liens est supérieur au nombre d'apparitions ... puis alimenter cette liste du. Mais si l'exigence est remplie, mieux vaut économiser l'effort.
angus
@StephaneChazelas Cela fonctionne, mais il est vrai qu'il ne tient pas compte de la taille des répertoires. Si seulement duavait un -dparamètre similaire à ls's ...
angus
Notez également que sur les btrfssystèmes de fichiers, le nombre de liens pour les répertoires est toujours 1, vous devez donc ajouter un! -type d
Stéphane Chazelas
5

Fondamentalement, vous devez obtenir les numéros d'inode et le nombre de liens pour tous les fichiers (non-répertoires), comparer ce nombre de liens avec le nombre d'occurrences de chaque inode et, s'ils diffèrent, exclure le fichier.

En supposant qu'ils sont tous sur le même système de fichiers, quelque chose comme ça devrait fonctionner (avec GNU find):

find . -type d -printf '%k\n' -o -printf '%i %n %k\n' |
   awk '
     NF==1{t+=$0; next}
     {n1[$1]=$2; n2[$1]++; s[$1]=$3}
     END {
       for (i in n1)
         if (n1[i] == n2[i])
           t+=s[i]
       print t
     }'
Stéphane Chazelas
la source
Ouais, ce que j'ai dit (merci pour le crédit). Mais la précision supplémentaire que vous obtenez en comptant les répertoires, vous perdez en ajoutant une utilisation inexacte du disque.
angus
@angus, qu'entendez-vous par "utilisation inexacte du disque"?
Stéphane Chazelas
Rien, je me suis totalement trompé sur ce qui a %kété rapporté. C'est super, ce dun'est pas nécessaire du tout! Je mettrai à jour ma réponse quand je rentrerai. Merci!
angus
3

du en réalité, il ne mentira pas;) Il analyse le ou les répertoires qu'on lui donne, en ne comptant que le premier de tous les liens physiques pointant vers le même inode qu'il rencontre.

Si vous demandez duce qu'il voit dans un seul répertoire, il ne se soucie pas qu'il existe d'autres liens durs pointant vers le même contenu:

$ du -h daily.0 && du -hc daily.1
29G /daily.0
29G /daily.1

Donnez-lui maintenant des répertoires sur la même ligne (en commençant par le plus récent pour les sauvegardes incrémentielles rsync avec --link-dest):

$ du -hc daily.0 daily.1
29G /daily.0
364M /daily.1
29G total

Ou tout le répertoire de sauvegarde:

$ du -hc --max-depth=1 /snapshots
29G /daily.0
364M /daily.1
537M /daily.2
333M /daily.3
30G total

Tout fichier dans 'daily.1' référençant un inode (aka "vrai" fichier) déjà référencé dans 'daily.0' ne sera pas compté.

Par conséquent, la suppression quotidienne.1 permettra d'économiser 364 Mo sur votre appareil.

RETIRER

tuk0z
la source