Jak `du` tylko przestrzeń zajmowaną przez pliki, które nie są dowiązane w inny sposób?

14

Używając rsync --link-destmigawek zajmujących mało miejsca, jak mogę dowiedzieć się, ile faktycznie zaoszczędziłem? Lub bardziej ogólnie:

Jak obliczyć, ile miejsca zajmuje katalog, biorąc pod uwagę tylko pliki, które nie są dowiązane w inny sposób poza strukturą katalogu? Pytanie zadane inaczej: Ile miejsca faktycznie zostanie zwolnione po usunięciu tego katalogu? ( du -hskłamałby. Można uwzględnić miejsce wymagane na same linki twarde)

Tobias Kienzler
źródło
2
Domyślnie GNU duzlicza rozmiary plików tylko raz, nawet jeśli są one mocno połączone, chyba że użyjesz opcji -l/ --count-links. Uruchomić duna całym drzewie dwa razy, zi bez tej opcji, a różnica pomiędzy wielkością powinna być jak dużo miejsca jest zapisany na wszystkie katalogi.
jw013,

Odpowiedzi:

9

Zakładając, że nie ma wewnętrznych dowiązań twardych (to znaczy, że każdy plik z więcej niż 1 dowiązaniem twardym jest połączony spoza drzewa), możesz:

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

EDYCJA I oto, co naszkicowałem w komentarzu, zastosowałem. Tylko bez du; pochwały dla @StephaneChazelas za zauważenie dunie jest konieczne. Wyjaśnienie na końcu.

( 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

To, co robimy, to utworzenie ciągu znaków z wykorzystaniem miejsca na dysku (w KB) każdego odpowiedniego pliku, oddzielonego znakami plus. Następnie karmimy ten duży dodatek bc.

Pierwsze findwywołanie robi to dla katalogów.

Drugi finddrukuje liczbę linków, i-węzłów i użycie dysku. Przekazujemy tę listę, sort | uniq -caby uzyskać listę (liczba wystąpień w drzewie, liczba linków, i-węzeł, użycie dysku).

Przekazujemy listę awk, a jeśli pierwsze pole (# wystąpień) jest większe lub równe drugiemu (# linków twardych), co oznacza, że ​​nie ma linków do tego pliku spoza drzewa, to wydrukujemy czwarte pole ( użycie dysku) ze znakiem plus i odwrotnym ukośnikiem.

Na koniec wypisujemy a 0, więc formuła jest poprawna pod względem składniowym (w +przeciwnym razie byłaby en ) i przekazana do bc. Uff

(Ale użyłbym pierwszej prostszej metody, jeśli daje wystarczająco dobrą odpowiedź.)

angus
źródło
Dzięki, tak, jeśli ten wymóg jest spełniony, działa. A jeśli tak nie jest?
Tobias Kienzler,
To nie działa, ponieważ nie uwzględnia wielkości samych katalogów (które zwykle mają co najmniej 2 linki, a gdyby nie, pliki byłyby liczone dwukrotnie).
Stéphane Chazelas
1
Konieczne byłoby wówczas findwydrukowanie listy wszystkich plików z ich i-węzłami i liczbą linków; następnie jakąś kombinację, sort | uniq -caby dowiedzieć się, ile razy każdy i-węzeł pojawia się w drzewie, a następnie odfiltrować te, których liczba łączy jest większa niż liczba wystąpień ... a następnie przesłać listę du. Ale jeśli warunek jest spełniony, lepiej oszczędzaj wysiłek.
angus
@StephaneChazelas Działa, ale prawdą jest, że nie uwzględnia własnego rozmiaru katalogów. Gdyby tylko dumiał -dparametr podobny do ls...
angus
Zauważ też, że w btrfssystemach plików liczba linków do katalogów jest zawsze 1, więc musisz dodać! -type d
Stéphane Chazelas
5

Zasadniczo musisz uzyskać numery i-węzłów i liczbę dowiązań dla wszystkich plików (bez katalogów), porównać tę liczbę dowiązań z liczbą wystąpień każdego i-węzła, a jeśli się różnią, wyklucz plik.

Zakładając, że wszystkie są w tym samym systemie plików, coś takiego powinno działać (z 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
źródło
Tak, co powiedziałem (dzięki za uznanie). Ale dodatkową dokładność, którą uzyskujesz, licząc katalogi, tracisz, dodając niedokładne użycie dysku.
angus
@angus, co rozumiesz przez „niedokładne użycie dysku”?
Stéphane Chazelas
Nic, całkowicie się myliłem co do tego, co %kzgłoszono. To świetnie, duwcale nie jest potrzebne! Zaktualizuję swoją odpowiedź, kiedy wrócę do domu. Dzięki!
angus
3

du tak naprawdę nie będzie kłamać;) Analizuje katalog, który daje, licząc tylko pierwsze hardlinks wskazujące na ten sam i-węzeł, który napotyka.

Jeśli zapytasz, duco widzi tylko w jednym katalogu, nie ma znaczenia, że ​​istnieją inne twarde linki prowadzące do tej samej zawartości:

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

Teraz nadaj mu katalogi w tym samym wierszu (zaczynając od najnowszego dla przyrostowych kopii zapasowych rsync z --link-dest):

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

Lub cały katalog kopii zapasowej:

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

Jakikolwiek plik w „Daily.1” odwołujący się do i-węzła (inaczej „plik rzeczywisty”) już wymieniony w „Daily.0” nie będzie liczony.

Dlatego codzienne usuwanie 1 pozwoli zaoszczędzić 364 MB na urządzeniu.

USUNĄĆ

tuk0z
źródło