Bagaimana cara `du` hanya ruang yang digunakan oleh file yang tidak di-hardlink di tempat lain?

14

Menggunakan rsync --link-destuntuk snapshot hemat-ruang , bagaimana saya bisa mengetahui berapa banyak ruang yang sebenarnya saya simpan? Atau lebih umum:

Bagaimana cara mengetahui berapa banyak ruang yang digunakan direktori dengan mempertimbangkan hanya file yang tidak di-hardlink di tempat lain di luar struktur direktori? Ditanyakan secara berbeda: Berapa banyak ruang yang benar-benar akan dibebaskan setelah penghapusan direktori itu? ( du -hsakan berbohong. Ruang yang dibutuhkan untuk hardlink sendiri mungkin termasuk)

Tobias Kienzler
sumber
2
Secara default, GNU duhanya menghitung ukuran file satu kali bahkan jika mereka terhubung keras kecuali Anda menggunakan opsi -l/ --count-links. Anda menjalankan duseluruh pohon dua kali, dengan dan tanpa opsi itu dan perbedaan antara ukuran harus berapa banyak ruang yang Anda simpan di semua direktori.
jw013

Jawaban:

9

Dengan asumsi tidak ada hardlink internal (yaitu, setiap file dengan lebih dari 1 hardlink ditautkan dari luar pohon), Anda dapat melakukannya:

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

EDIT Dan inilah yang saya sketsa di komentar, diterapkan. Hanya tanpa du; kudos to @StephaneChazelas untuk memperhatikan dutidak perlu. Penjelasan di akhir.

( 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

Apa yang kami lakukan adalah membuat string dengan penggunaan disk (dalam KB) dari setiap file yang relevan, dipisahkan dengan tanda plus. Lalu kami memberi makan tambahan besar itu bc.

findDoa pertama melakukannya untuk direktori.

findCetakan kedua menghitung jumlah penghitungan, inode, dan penggunaan disk. Kami melewati daftar itu sort | uniq -cuntuk mendapatkan daftar (jumlah tampilan di pohon, jumlah tautan, inode, penggunaan disk).

Kami melewati bahwa daftar melalui awk, dan, jika field pertama (# dari penampilan) lebih besar dari atau sama kedua (# dari hardlinks), yang berarti tidak ada link ke file ini dari luar pohon, kemudian mencetak lapangan keempat ( penggunaan disk) dengan tanda plus dan garis miring terbalik.

Akhirnya kita menghasilkan a 0, jadi rumusnya secara sintaksis benar (itu akan menjadi +sebaliknya) dan meneruskannya ke bc. Fiuh.

(Tapi saya akan menggunakan metode pertama yang lebih sederhana, jika itu memberikan jawaban yang cukup baik.)

angus
sumber
Terima kasih, ya jika persyaratan itu terpenuhi berfungsi. Tetapi bagaimana jika tidak?
Tobias Kienzler
Itu tidak berfungsi karena gagal memperhitungkan ukuran direktori itu sendiri (yang biasanya memiliki setidaknya 2 tautan, dan jika tidak, Anda harus menghitung file dua kali).
Stéphane Chazelas
1
Maka akan perlu digunakan finduntuk mencetak daftar semua file dengan inode dan jumlah tautannya; lalu beberapa kombinasi sort | uniq -cuntuk mendapatkan berapa kali setiap inode muncul di pohon, lalu saring yang dengan jumlah tautan lebih besar dari jumlah penampilan ... dan kemudian masukkan daftar itu ke du. Tetapi jika persyaratannya terpenuhi, lebih baik selamatkan usahanya.
angus
@StephaneChazelas Ini memang berfungsi, tapi memang benar itu tidak memperhitungkan ukuran direktori sendiri. Andai saja duada -dparameter yang mirip dengan ls...
angus
Juga perhatikan bahwa pada btrfssistem file, jumlah tautan untuk direktori selalu 1, jadi Anda perlu menambahkan! -type d
Stéphane Chazelas
5

Pada dasarnya, Anda perlu mendapatkan nomor inode dan jumlah tautan untuk semua file (non-direktori), bandingkan jumlah tautan dengan jumlah kemunculan setiap inode, dan jika berbeda, kecualikan file tersebut.

Dengan asumsi, mereka semua berada di sistem file yang sama, sesuatu seperti ini seharusnya bekerja (dengan 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
sumber
Ya, apa yang saya katakan (terima kasih atas kreditnya). Tetapi akurasi ekstra yang Anda dapatkan dengan menghitung direktori, Anda kehilangan dengan menambahkan penggunaan disk tidak tepat.
angus
@ Kangus, apa yang Anda maksud dengan "penggunaan disk tidak tepat"?
Stéphane Chazelas
Tidak ada, saya benar-benar keliru tentang apa yang %kdilaporkan. Itu hebat, dutidak diperlukan sama sekali! Saya akan memperbarui jawaban saya ketika saya pulang. Terima kasih!
angus
3

du sebenarnya tidak akan berbohong;) Ini mem-parsing dir (s) yang diberikannya, menghitung hanya yang pertama dari semua hardlink yang menunjuk ke inode yang sama yang dihadapinya.

Jika Anda bertanya duapa yang dilihatnya dalam satu direktori saja, itu tidak peduli bahwa ada tautan keras lain yang menunjuk ke konten yang sama:

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

Sekarang berikan dirs pada baris yang sama (dimulai dengan yang terbaru untuk rsync incremental backups with --link-dest):

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

Atau seluruh dir cadangan:

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

File apa pun di 'daily.1' yang merujuk pada inode (alias file "asli") yang telah dirujuk dalam 'daily.0' tidak akan dihitung.

Karena itu menghapus setiap hari.1 akan menghemat 364MB di perangkat Anda.

MENGHAPUS

tuk0z
sumber