saya berlari
ln /a/A /b/B
Saya ingin melihat folder a
tempat file A menunjuk ls
.
saya berlari
ln /a/A /b/B
Saya ingin melihat folder a
tempat file A menunjuk ls
.
Jawaban:
Anda dapat menemukan nomor inode untuk file Anda
ls -i
dan
ls -l
menunjukkan jumlah referensi (jumlah hardlink ke inode tertentu)
setelah Anda menemukan nomor inode, Anda dapat mencari semua file dengan inode yang sama:
find . -inum NUM
akan menampilkan nama file untuk inode NUM di dir saat ini (.)
Sebenarnya tidak ada jawaban yang jelas untuk pertanyaan Anda. Tidak seperti symlink, hardlink tidak dapat dibedakan dari "file asli".
Entri direktori terdiri dari nama file dan penunjuk ke inode. Inode pada gilirannya berisi metadata file dan (menunjuk ke) isi file yang sebenarnya). Membuat tautan keras membuat nama file + referensi lain ke inode yang sama. Referensi ini bersifat searah (setidaknya dalam sistem file biasa) - inode hanya menyimpan jumlah referensi. Tidak ada cara intrinsik untuk mengetahui nama file mana yang "asli".
Ngomong-ngomong, inilah mengapa system call untuk "menghapus" file dipanggil unlink
. Itu hanya menghapus hardlink. Inode data yang dilampirkan dihapus hanya jika jumlah referensi inode turun menjadi 0.
Satu-satunya cara untuk menemukan referensi lain ke inode yang diberikan adalah mencari sistem file secara menyeluruh memeriksa file mana yang merujuk ke inode yang dimaksud. Anda dapat menggunakan 'test A -ef B' dari shell untuk melakukan pemeriksaan ini.
UNIX memiliki tautan keras dan tautan simbolik (dibuat dengan "ln"
dan "ln -s"
masing - masing). Tautan simbolik hanyalah sebuah file yang berisi jalur asli ke file lain dan dapat melintasi sistem file.
Tautan keras telah ada sejak masa-masa awal UNIX (yang dapat saya ingat pula, dan itu akan kembali cukup lama). Mereka adalah dua entri direktori yang mereferensikan data dasar yang sama persis . Data dalam file ditentukan oleh inode
. Setiap file pada sistem file menunjuk ke inode tetapi tidak ada persyaratan bahwa setiap file menunjuk ke inode yang unik - dari situlah hard link berasal.
Karena inode hanya unik untuk sistem file yang diberikan, ada batasan bahwa tautan keras harus berada di sistem file yang sama (tidak seperti tautan simbolik). Perhatikan bahwa, tidak seperti tautan simbolis, tidak ada file istimewa - semuanya sama. Area data hanya akan dirilis ketika semua file yang menggunakan inode itu dihapus (dan semua proses menutupnya juga, tapi itu masalah yang berbeda).
Anda dapat menggunakan "ls -i"
perintah untuk mendapatkan inode dari file tertentu. Anda kemudian dapat menggunakan "find <filesystemroot> -inum <inode>"
perintah untuk menemukan semua file di sistem file dengan inode yang diberikan.
Inilah skrip yang melakukan hal itu. Anda memohonnya dengan:
findhardlinks ~/jquery.js
dan ia akan menemukan semua file pada sistem file itu yang merupakan tautan keras untuk file itu:
pax@daemonspawn:~# ./findhardlinks /home/pax/jquery.js
Processing '/home/pax/jquery.js'
'/home/pax/jquery.js' has inode 5211995 on mount point '/'
/home/common/jquery-1.2.6.min.js
/home/pax/jquery.js
Ini skripnya.
#!/bin/bash
if [[ $# -lt 1 ]] ; then
echo "Usage: findhardlinks <fileOrDirToFindFor> ..."
exit 1
fi
while [[ $# -ge 1 ]] ; do
echo "Processing '$1'"
if [[ ! -r "$1" ]] ; then
echo " '$1' is not accessible"
else
numlinks=$(ls -ld "$1" | awk '{print $2}')
inode=$(ls -id "$1" | awk '{print $1}' | head -1l)
device=$(df "$1" | tail -1l | awk '{print $6}')
echo " '$1' has inode ${inode} on mount point '${device}'"
find ${device} -inum ${inode} 2>/dev/null | sed 's/^/ /'
fi
shift
done
. ./findhardlinks.bash
berada di OS X Zsh. Jendela saya saat ini di Layar ditutup.
INUM=$(stat -c %i $1)
. Juga NUM_LINKS=$(stat -c %h $1)
. Lihat man stat
untuk variabel format lainnya yang dapat Anda gunakan.
ls -l
Kolom pertama akan mewakili izin. Kolom kedua adalah jumlah sub-item (untuk direktori) atau jumlah jalur ke data yang sama (tautan keras, termasuk file asli) ke file. Misalnya:
-rw-r--r--@ 2 [username] [group] [timestamp] HardLink
-rw-r--r--@ 2 [username] [group] [timestamp] Original
^ Number of hard links to the data
inode
mana pada gilirannya menunjuk ke konten disk.
Bagaimana dengan yang lebih sederhana berikut ini? (Belakangan mungkin mengganti skrip panjang di atas!)
Jika Anda memiliki file tertentu <THEFILENAME>
dan ingin tahu semua hardlink-nya tersebar di direktori <TARGETDIR>
, (yang bahkan bisa menjadi seluruh sistem file yang ditandai oleh /
)
find <TARGETDIR> -type f -samefile <THEFILENAME>
Memperluas logika, jika Anda ingin mengetahui semua file dalam <SOURCEDIR>
memiliki banyak tautan keras tersebar di <TARGETDIR>
:
find <SOURCEDIR> -type f -links +1 \
-printf "\n\n %n HardLinks of file : %H/%f \n" \
-exec find <TARGETDIR> -type f -samefile {} \;
-type f
karena file juga dapat menjadi direktori.
.
dan ..
entri dalam direktori adalah hardlinks. Anda dapat mengetahui berapa banyak subdir dalam direktori dari jumlah tautan .
. Ini masih bisa diperdebatkan, karena find -samefile .
masih tidak akan mencetak subdir/..
output apa pun . find
(setidaknya versi GNU) tampaknya hardcoded untuk diabaikan ..
, bahkan dengan -noleaf
.
O(n^2)
, dan berjalan find
sekali untuk setiap anggota dari sekumpulan file yang di-hardlink. find ... -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate
akan bekerja, (16 tidak cukup lebar untuk representasi desimal 2 ^ 63-1, jadi ketika sistem file XFS Anda cukup besar untuk memiliki nomor inode yang tinggi, hati-hati)
Ada banyak jawaban dengan skrip untuk menemukan semua hardlink di sistem file. Sebagian besar dari mereka melakukan hal-hal konyol seperti menjalankan find untuk memindai seluruh sistem file -samefile
untuk setiap file yang terhubung multipel. Ini gila; yang Anda butuhkan hanyalah mengurutkan pada nomor inode dan mencetak duplikat.
Dengan hanya satu melewati filesystem untuk menemukan dan mengelompokkan semua set file yang di-link
find dirs -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
sort -n | uniq -w 42 --all-repeated=separate
Ini jauh lebih cepat daripada jawaban lain untuk menemukan beberapa set file yang di-hardlink.
find /foo -samefile /bar
sangat bagus untuk hanya satu file.
-xdev
: batasi ke satu sistem file. Tidak sepenuhnya diperlukan karena kami juga mencetak FS-id untuk di-uniq! -type d
tolak direktori: entri .
dan ..
artinya mereka selalu ditautkan.-links +1
: penghitungan tautan dengan ketat > 1
-printf ...
cetak FS-id, nomor inode, dan path. (Dengan padding untuk memperbaiki lebar kolom yang bisa kami ceritakan uniq
.)sort -n | uniq ...
pengurutan numerik dan uniquify pada 42 kolom pertama, pisahkan grup dengan garis kosongMenggunakan ! -type d -links +1
berarti input sortir hanya sebesar output akhir dari uniq jadi kami tidak melakukan sejumlah besar penyortiran string. Kecuali Anda menjalankannya pada subdirektori yang hanya berisi satu dari sekumpulan hardlink. Bagaimanapun, ini akan menggunakan BANYAK waktu CPU yang lebih sedikit untuk melintasi kembali sistem file daripada solusi yang diposting lainnya.
output sampel:
...
2429 76732484 /home/peter/weird-filenames/test/.hiddendir/foo bar
2429 76732484 /home/peter/weird-filenames/test.orig/.hiddendir/foo bar
2430 17961006 /usr/bin/pkg-config.real
2430 17961006 /usr/bin/x86_64-pc-linux-gnu-pkg-config
2430 36646920 /usr/lib/i386-linux-gnu/dri/i915_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/i965_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/nouveau_vieux_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/r200_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/radeon_dri.so
...
TODO ?: batalkan keluaran dengan awk
atau cut
. uniq
memiliki dukungan pemilihan bidang yang sangat terbatas, jadi saya mencari hasil keluaran dan menggunakan lebar tetap. 20chars cukup lebar untuk inode atau nomor perangkat maksimum yang dimungkinkan (2 ^ 64-1 = 18446744073709551615). XFS memilih nomor inode berdasarkan di mana pada disk mereka dialokasikan, tidak bersebelahan dari 0, sehingga sistem file XFS besar dapat memiliki nomor inode> 32bit bahkan jika mereka tidak memiliki miliaran file. Sistem file lain mungkin memiliki nomor inode 20 digit bahkan jika mereka tidak raksasa.
TODO: mengurutkan grup duplikat berdasarkan jalur. Setelah mereka diurutkan berdasarkan mount point kemudian nomor inode mencampur semuanya, jika Anda memiliki beberapa subdir yang berbeda yang memiliki banyak hardlink. (Yaitu grup dup-kelompok berjalan bersama, tetapi output mencampurnya).
Final sort -k 3
akan mengurutkan garis secara terpisah, bukan kelompok garis sebagai rekaman tunggal. Memproses ulang dengan sesuatu untuk mengubah sepasang baris baru ke byte NUL, dan menggunakan GNU sort --zero-terminated -k 3
mungkin melakukan trik. tr
hanya beroperasi pada karakter tunggal, bukan 2-> 1 atau 1-> 2 pola. perl
akan melakukannya (atau hanya menguraikan dan mengurutkan dalam perl atau awk). sed
mungkin juga berfungsi.
%D
adalah filesystem identifier (itu adalah unik untuk boot saat ini sementara tidak ada filesystem yang umount
ed), sehingga berikut ini bahkan lebih generik: find directories.. -xdev ! -type d -links +1 -printf '%20i %20D %p\n' | sort -n | uniq -w 42 --all-repeated=separate
. Ini berfungsi selama tidak ada direktori yang berisi direktori lain pada tingkat filesystem, juga terlihat pada semua yang dapat di-hardlink (seperti perangkat atau softlink - ya, softlink dapat memiliki jumlah tautan lebih dari 1). Catat itu dev_t
dan ino_t
panjangnya 64 bit hari ini. Ini kemungkinan akan bertahan selama kita memiliki sistem 64 bit.
! -type d
, bukan -type f
. Saya bahkan memiliki beberapa symlink hardlink pada sistem file saya dari mengatur beberapa koleksi file. Memperbarui jawaban saya dengan versi perbaikan Anda (tapi saya menempatkan fs-id pertama, jadi urutan setidaknya kelompok berdasarkan sistem file.)
Ini agak komentar untuk jawaban dan skrip Torocoro-Macho sendiri, tetapi jelas tidak cocok di kotak komentar.
Menulis ulang skrip Anda dengan cara yang lebih mudah untuk menemukan info, dan dengan demikian proses pemanggilan jauh lebih sedikit.
#!/bin/sh
xPATH=$(readlink -f -- "${1}")
for xFILE in "${xPATH}"/*; do
[ -d "${xFILE}" ] && continue
[ ! -r "${xFILE}" ] && printf '"%s" is not readable.\n' "${xFILE}" 1>&2 && continue
nLINKS=$(stat -c%h "${xFILE}")
if [ ${nLINKS} -gt 1 ]; then
iNODE=$(stat -c%i "${xFILE}")
xDEVICE=$(stat -c%m "${xFILE}")
printf '\nItem: %s[%d] = %s\n' "${xDEVICE}" "${iNODE}" "${xFILE}";
find "${xDEVICE}" -inum ${iNODE} -not -path "${xFILE}" -printf ' -> %p\n' 2>/dev/null
fi
done
Saya mencoba menjaganya agar tetap serupa dengan milik Anda agar mudah untuk perbandingan.
Orang harus selalu menghindari $IFS
keajaiban jika gumpalan cukup, karena tidak perlu berbelit-belit, dan nama file sebenarnya dapat berisi baris baru (tetapi dalam praktiknya sebagian besar alasan pertama).
Anda harus menghindari penguraian secara manual ls
dan output sebanyak mungkin, karena akan cepat atau lambat akan menggigit Anda. Misalnya: di awk
baris pertama Anda, Anda gagal pada semua nama file yang berisi spasi.
printf
akan sering menyimpan masalah pada akhirnya karena sangat kuat dengan %s
sintaksis. Ini juga memberi Anda kontrol penuh atas output, dan konsisten di semua sistem, tidak seperti echo
.
stat
dapat menghemat banyak logika dalam hal ini.
GNU find
sangat kuat.
Anda head
dan tail
doa bisa ditangani secara langsung awk
dengan misalnya exit
perintah dan / atau memilih NR
variabel. Ini akan menghemat pemanggilan proses, yang hampir selalu menyaingi kinerja yang parah dalam skrip yang bekerja keras.
egrep
S Anda bisa saja adil grep
.
find ... -xdev -type f -links +1 -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate
. Ini JAUH lebih cepat, karena hanya melintasi fs sekali. Untuk beberapa FS sekaligus, Anda harus awalan nomor inode dengan id FS. Mungkin denganfind -exec stat... -printf ...
Berdasarkan findhardlinks
skrip (diubah namanya menjadi hard-links
), inilah yang telah saya refactored dan membuatnya berfungsi.
Keluaran:
# ./hard-links /root
Item: /[10145] = /root/.profile
-> /proc/907/sched
-> /<some-where>/.profile
Item: /[10144] = /root/.tested
-> /proc/907/limits
-> /<some-where else>/.bashrc
-> /root/.testlnk
Item: /[10144] = /root/.testlnk
-> /proc/907/limits
-> /<another-place else>/.bashrc
-> /root/.tested
# cat ./hard-links
#!/bin/bash
oIFS="${IFS}"; IFS=$'\n';
xPATH="${1}";
xFILES="`ls -al ${xPATH}|egrep "^-"|awk '{print $9}'`";
for xFILE in ${xFILES[@]}; do
xITEM="${xPATH}/${xFILE}";
if [[ ! -r "${xITEM}" ]] ; then
echo "Path: '${xITEM}' is not accessible! ";
else
nLINKS=$(ls -ld "${xITEM}" | awk '{print $2}')
if [ ${nLINKS} -gt 1 ]; then
iNODE=$(ls -id "${xITEM}" | awk '{print $1}' | head -1l)
xDEVICE=$(df "${xITEM}" | tail -1l | awk '{print $6}')
echo -e "\nItem: ${xDEVICE}[$iNODE] = ${xITEM}";
find ${xDEVICE} -inum ${iNODE} 2>/dev/null|egrep -v "${xITEM}"|sed 's/^/ -> /';
fi
fi
done
IFS="${oIFS}"; echo "";
Solusi GUI sangat dekat dengan pertanyaan Anda:
Anda tidak dapat membuat daftar file yang di-hardlink dari "ls" karena, seperti yang ditunjukkan oleh komentator sebelumnya, file "nama" hanyalah alias untuk data yang sama. Namun, sebenarnya ada alat GUI yang mendekati apa yang Anda inginkan yaitu untuk menampilkan daftar path nama file yang mengarah ke data yang sama (seperti hardlink) di linux, itu disebut FSLint. Opsi yang Anda inginkan ada di bawah "Nama bentrokan" -> hapus centang "kotak centang $ PATH" di Cari (XX) -> dan pilih "Alias" dari kotak drop-down setelah "untuk ..." menuju ke tengah-atas.
FSLint didokumentasikan dengan sangat buruk tetapi saya menemukan bahwa memastikan pohon direktori terbatas di bawah "Jalur pencarian" dengan kotak centang yang dipilih untuk "Recurse?" dan opsi-opsi yang disebutkan di atas, daftar data yang di-hardlink dengan jalur dan nama yang "menunjuk" ke data yang sama dihasilkan setelah pencarian program.
Anda dapat mengonfigurasi ls
untuk menyoroti hardlink menggunakan 'alias', tetapi seperti yang dinyatakan sebelumnya tidak ada cara untuk menunjukkan 'sumber' dari hardlink itu sebabnya saya menambahkan .hardlink
untuk membantu dengan itu.
Tambahkan berikut ini di suatu tempat di Anda .bashrc
alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
link(2)
pemanggilan sistem, tidak ada arti di mana yang asli dan yang satu adalah tautan. Inilah sebabnya, seperti yang ditunjukkan jawabannya, satu-satunya cara untuk menemukan semua tautan adalahfind / -samefile /a/A
. Karena satu entri direktori untuk inode tidak "tahu tentang" entri direktori lain untuk inode yang sama. Yang mereka lakukan adalah menghitung ulang inode sehingga bisa dihapus ketika nama terakhirnyaunlink(2)ed
. (Ini adalah "jumlah tautan" dalamls
output).