Bagaimana saya bisa menemukan semua file yang di-hardlink pada sistem file?

21

Saya perlu menemukan semua file yang di-hardlink pada sistem file yang diberikan. Misalnya mendapatkan daftar file, setiap baris berisi pasangan yang terhubung, atau kembar tiga, dll.

Saya mengerti kurang lebih bagaimana melakukannya, kita perlu membuat kamus yang dikunci oleh inode untuk semua file / direktori pada sistem file, kecuali "." dan tautan "..", dan kemudian indode dengan lebih dari satu nama adalah hardlink ... Tapi saya harap mungkin ada solusi yang sudah ada, atau seseorang sudah menulis skrip seperti itu.

haim
sumber

Jawaban:

17

Anda dapat menjalankan perintah berikut:

find / -type f -printf '%n %p\n' | awk '$1 > 1{$1="";print}'

untuk menemukan semua file yang ditautkan dengan keras.

Atau versi @mbafford:

find / -type f -links +1 -printf '%i %n %p\n'
Gilles Quenot
sumber
1
Terima kasih, ini bukan yang saya inginkan, tetapi cukup dekat. Saya dapat menambahkan '% i' untuk mencetak nomor inode dan kemudian mengurutkan / mengelompokkannya ...
haimg
15
Anda dapat menghindari kebutuhan awk dengan menggunakan sintaks "-links + n 'find. Mis. Untuk menemukan semua file dengan setidaknya dua tautan dan mencetak info yang diperlukan:find / -type f -links +1 -printf '%i %n %p\n'
mbafford
bagaimana dengan piping melalui sort(+ uniq)? Saya penasaran jadi mencobanya di komputer utama saya (16GB i5-2500k dengan SSD). dengan 2187757 file ( find / -xdev -type f | wc) membutuhkan 12 detik nyata saat mengembalikan 3820 file / 570 inode ( time sudo find / -xdev -type f -links +1 -printf "%i\n" | sort | uniq | wc). Anda harus memasukkan %n %puntuk file yang sebenarnya karena saya mengambilnya untuk menghitung inode.
north-bradley
17
find . -type f -links +1 2>/dev/null

memberikan daftar semua file yang memiliki lebih dari satu tautan, yaitu file yang terdapat tautan keras. Melompati hal ini relatif mudah - solusi peretasan jika Anda tidak memiliki banyak file

for i in $(find . -type f -links +1 2>/dev/null); do find -samefile $i | awk '{printf "%s ", $1}'; printf "\n"; done | sort | uniq

Tapi saya sangat berharap bahwa ada solusi yang lebih baik, misalnya dengan membiarkan pertama findpanggilan nomor cetak inode dan kemudian menggunakan find's -inumpilihan untuk menampilkan semua file yang terkait dengan inode ini.

Claudius
sumber
1
Aduh! Ini memindai sistem file berulang-ulang untuk setiap file yang di-hardlink ...
haimg
1
Saya tidak mengklaim itu cepat - dan itu semacam bekerja untuk pohon direktori kecil. Tentu saja, indeks yang tepat, yang dapat dibangun dari, misalnya, output dari find . -type f -printf '%i %p\n', akan memungkinkan seseorang untuk membangun solusi yang jauh lebih cepat.
Claudius
Dan itu tidak menangani ruang di jalur AFAIK.
Gilles Quenot
Untuk forloop, menyesuaikan IFS sesuai akan berhasil. Untuk mem-parsing output dari perintah find dalam komentar saya, menyatakan semuanya antara spasi pertama dan akhir baris sebagai nama file harus bekerja juga.
Claudius
1
@Sati: memastikan bahwa pesan kesalahan dibuang (mis. Untuk folder yang tidak Anda sukai, lost+founddll.); yang sangat penting, jika output harus diproses lebih lanjut seperti pada baris kedua.
DJCrashdummy
1

IMHO cara terbaik adalah dengan menggunakan baris berikut (pasti Anda harus mengganti /PATH/FOR/SEARCH/dengan apa pun yang ingin Anda cari):

find /PATH/FOR/SEARCH/ -xdev -printf '%i\t%n\t%p\n' | fgrep -f <(find . -xdev -printf '%i\n' | sort -n | uniq -d) | sort -n

ini memindai sistem file hanya sekali, menunjukkan inode, jumlah hardlink dan jalur file dengan lebih dari satu hardlink dan mengurutkannya sesuai dengan inode.

jika Anda terganggu oleh pesan kesalahan untuk folder yang Anda tidak boleh baca, Anda dapat memperluas baris ke ini:

find /PATH/FOR/SEARCH/ -xdev -printf '%i\t%n\t%p\n' 2> /dev/null | fgrep -f <(find . -xdev -printf '%i\n' 2> /dev/null | sort -n | uniq -d) | sort -n
DJCrashdummy
sumber