it-swarm.asia

Bagaimana Anda bisa melihat tautan keras yang sebenarnya oleh ls?

Saya berlari

ln /a/A /b/B

Saya ingin melihat di folder a di mana file A menunjuk ke ls.

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 (.)

163
zzr

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 tipikal) - 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 disebut 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.

60

UNIX memiliki tautan keras dan tautan simbolik (dibuat dengan "ln" dan "ln -s" secara berurutan). 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 tepat data dasar yang sama. Data dalam file ditentukan oleh inode-nya. 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 perintah "ls -i" untuk mendapatkan inode dari file tertentu. Anda kemudian dapat menggunakan perintah "find <filesystemroot> -inum <inode>" untuk menemukan semua file pada sistem file dengan inode yang diberikan.

Inilah skrip yang melakukan hal itu. Anda memohonnya dengan:

findhardlinks ~/jquery.js

dan ia akan menemukan semua file di sistem file itu yang merupakan tautan keras untuk file itu:

[email protected]:~# ./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
33
user53528
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:

[email protected]    2    [username]    [group]    [timestamp]     HardLink
[email protected]    2    [username]    [group]    [timestamp]     Original
               ^ Number of hard links to the data
24
eyelidlessness

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 dilambangkan oleh /)

find <TARGETDIR> -type f -samefile  <THEFILENAME>

Memperluas logika, jika Anda ingin mengetahui semua file di <SOURCEDIR> memiliki banyak hard-link yang 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 {} \; 
11

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 untuk -samefile untuk setiap file yang terhubung multipel. Ini gila; yang Anda butuhkan hanyalah mengurutkan pada nomor inode dan mencetak duplikat.

find directories.. -xdev ! -type d -links +1 -printf '%20D %20i %p\n' | sort -n | uniq -w 42 --all-repeated=separate (Terima kasih kepada @Tino untuk mengutak-atik perintah asli saya untuk mendukung FS-id (%D), dan untuk menangani semua jenis file non-direktori, bukan hanya file biasa. Ini akan menemukan symlink, link, multiply-linked Anda yang terhubung dengan banyak pipa

Menggunakan ! -type d -links +1 berarti input sort hanya sebesar output akhir dari uniq. Kecuali Anda menjalankannya pada subdirektori yang hanya berisi satu dari sekumpulan hardlink. Bagaimanapun, ini akan menggunakan BANYAK waktu CPU yang lebih sedikit untuk menelusuri ulang sistem file daripada solusi yang diposting lainnya.

keluaran 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. 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 yang 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 mencampurkan berbagai hal, jika Anda memiliki beberapa subdir yang berbeda yang memiliki banyak hardlink. (mis. grup dup-grup berjalan bersama, tetapi hasilnya mencampurnya).

sort -k 3 akhir akan mengurutkan baris 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.

4
Peter Cordes

Ini sedikit 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.

Komentar pada skrip ini dan milik Anda

  • Kita harus selalu menghindari sihir $IFS jika glob sudah mencukupi, karena itu tidak perlu berbelit-belit, dan nama file sebenarnya dapat berisi baris baru (tetapi dalam praktiknya kebanyakan alasan pertama).

  • Anda harus menghindari penguraian ls secara manual dan output seperti itu sebanyak mungkin, karena akan cepat atau lambat akan menggigit Anda. Misalnya: pada baris awk pertama Anda, Anda gagal pada semua nama file yang berisi spasi.

  • printf akan sering menyelamatkan masalah pada akhirnya karena sangat kuat dengan sintaks %s. Ini juga memberi Anda kontrol penuh atas output, dan konsisten di seluruh semua sistem, tidak seperti echo.

  • stat dapat menghemat banyak logika dalam hal ini.

  • GNU find sangat kuat.

  • Doa head dan tail Anda dapat ditangani langsung di awk dengan mis. perintah exit dan/atau memilih pada variabel NR. Ini akan menghemat pemanggilan proses, yang hampir selalu menyaingi kinerja yang parah dalam skrip yang bekerja keras.

  • egreps Anda bisa juga hanya greps.

3
Daniel Andersson

Berdasarkan skrip findhardlinks (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 "";
2
Torocoro-Macho

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 path dan nama yang "menunjuk" ke data yang sama dihasilkan setelah pencarian program.

1
Charles

Anda dapat mengonfigurasi ls untuk menyorot hardlink menggunakan 'alias', tetapi seperti yang dinyatakan sebelumnya tidak ada cara untuk menunjukkan 'sumber' hardlink itu sebabnya saya menambahkan .hardlink untuk membantu dengan itu.

highlight hardlinks

Tambahkan berikut ini di suatu tempat di .bashrc Anda

alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
1