Como usar 'du' apenas o espaço usado pelos arquivos que não são hardlinked em outro lugar?

14

Usando rsync --link-dest para instantâneos que economizam espaço , como posso descobrir quanto espaço eu realmente salvei? ? Ou mais geral:

How to figure out how much space a directory uses considering only files that are not hardlinked elsewhere outside the directory structure? Asked differently: How much space would actually be freed after a deletion of that directory? (du -hs would lie. The space required for the hardlinks themselves may be included)

    
por Tobias Kienzler 25.10.2012 / 15:24

3 respostas

9

Supondo que não há links internos (ou seja, cada arquivo com mais de um link está vinculado fora da árvore), você pode fazer:

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

EDITAR E aqui está o que eu esbocei no comentário, aplicado. Apenas sem du ; Muitos elogios para @StephaneChazelas por perceber du não são necessários. Explicação no final.

( 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

O que fazemos é criar uma string com o uso do disco (em KB) de cada arquivo relevante, separado por sinais de mais. Então nós alimentamos essa grande adição a bc .

A primeira invocação de find faz isso para diretórios.

O segundo find imprime a contagem de links, o inode e o uso do disco. Passamos essa lista através de sort | uniq -c para obter uma lista de (número de aparições na árvore, contagem de links, inode, uso de disco).

Passamos essa lista por awk e, se o primeiro campo (nº de aparências) for maior ou igual ao segundo (# de hardlinks), o que significa que não há links para este arquivo de fora da árvore, em seguida, imprima o quarto campo (uso do disco) com um sinal de mais e uma barra invertida anexada.

Por fim, geramos um 0 , portanto, a fórmula está sintaticamente correta (seria em + caso contrário) e passaria para bc . Ufa.

(Mas eu usaria o primeiro método mais simples, se ele der uma resposta boa o suficiente.)

    
por 25.10.2012 / 15:36
5

Basicamente, você precisa obter os números de inode e o número de links para todos os arquivos (não-diretórios), comparar esse número de link com o número de ocorrências de cada inode e, se eles diferirem, excluir o arquivo. / p>

Supondo que eles estejam todos no mesmo sistema de arquivos, algo assim deve funcionar (com o 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
     }'
    
por 25.10.2012 / 16:03
3

du actualy não vai mentir;) Analisa o (s) dir (s) que se dá, contando apenas o primeiro de todos os hardlinks apontando para o mesmo inode que encontra.

Se você perguntar a du o que ele vê em apenas um diretório, não importa se há outros links físicos apontando para o mesmo conteúdo:

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

Agora, dê a ele dirs na mesma linha (começando com o mais recente para backups incrementais de rsync com --link-dest ):

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

Ou o diretório de backup completo:

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

Qualquer arquivo em 'daily.1' referenciando um inode (também conhecido como arquivo "real") já referenciado em 'daily.0' não será contado.

Portanto, a exclusão diária.1 salvará 364 MB no seu dispositivo.

REMOVER

    
por 24.02.2015 / 14:03