Bagaimana saya dapat menemukan symlink yang rusak

282

Apakah ada cara untuk menemukan semua tautan simbolik yang tidak mengarah ke mana pun?

find ./ -type l

akan memberi saya semua tautan simbolis, tetapi tidak membuat perbedaan antara tautan yang pergi ke suatu tempat dan tautan yang tidak.

Saya sedang melakukan:

find ./ -type l -exec file {} \; |grep broken

Tapi saya bertanya-tanya solusi alternatif apa yang ada.

kawan
sumber

Jawaban:

351

Saya sangat menyarankan untuk tidak menggunakan find -L untuk tugas (lihat di bawah untuk penjelasan). Berikut ini beberapa cara lain untuk melakukan ini:

  • Jika Anda ingin menggunakan metode "murni find", itu akan terlihat seperti ini:

    find . -xtype l
    

    ( xtypeadalah tes yang dilakukan pada tautan yang direferensikan). Namun, ini mungkin tidak tersedia di semua versi find. Tetapi ada opsi lain juga:

  • Anda juga dapat mengeksekusi test -edari dalam findperintah:

    find . -type l ! -exec test -e {} \; -print
    
  • Bahkan beberapa greptrik bisa lebih baik (yaitu, lebih aman ) daripada find -L, tetapi tidak persis seperti yang disajikan dalam pertanyaan (yang menangkap di seluruh lini output, termasuk nama file):

     find . -type l -exec sh -c 'file -b "$1" | grep -q ^broken' sh {} \; -print
    

The find -Ltrick dikutip oleh pasangan dari commandlinefu terlihat bagus dan Hacky, tetapi memiliki satu sangat perangkap berbahaya : Semua symlink diikuti. Pertimbangkan direktori dengan konten yang disajikan di bawah ini:

$ ls -l
total 0
lrwxrwxrwx 1 michal users  6 May 15 08:12 link_1 -> nonexistent1
lrwxrwxrwx 1 michal users  6 May 15 08:13 link_2 -> nonexistent2
lrwxrwxrwx 1 michal users  6 May 15 08:13 link_3 -> nonexistent3
lrwxrwxrwx 1 michal users  6 May 15 08:13 link_4 -> nonexistent4
lrwxrwxrwx 1 michal users 11 May 15 08:20 link_out -> /usr/share/

Jika Anda menjalankan find -L . -type ldi direktori itu, semua /usr/share/akan dicari juga (dan itu bisa memakan waktu sangat lama) 1 . Untuk findperintah yang "kebal terhadap tautan keluar", jangan gunakan-L .


1 Ini mungkin terlihat seperti ketidaknyamanan kecil (perintah akan "hanya" membutuhkan waktu lama untuk melintasi semua /usr/share) - tetapi dapat memiliki konsekuensi yang lebih parah. Sebagai contoh, pertimbangkan lingkungan chroot: Mereka dapat ada di beberapa subdirektori dari sistem file utama dan berisi symlink ke lokasi absolut. Tautan tersebut tampaknya rusak untuk sistem "luar", karena tautan tersebut hanya menunjuk ke tempat yang tepat setelah Anda memasuki chroot. Saya juga ingat bahwa beberapa bootloader menggunakan symlinks di bawah /bootyang hanya masuk akal pada fase boot awal, ketika partisi boot dipasang sebagai /.

Jadi jika Anda menggunakan find -Lperintah untuk menemukan dan kemudian menghapus symlink yang rusak dari beberapa direktori yang tampak tidak berbahaya, Anda bahkan mungkin merusak sistem Anda ...

rozcietrzewiacz
sumber
11
Saya pikir -type lini berlebihan karena -xtype lakan beroperasi -type lpada non-tautan. Jadi find -xtype lmungkin itulah yang Anda butuhkan. Terima kasih atas pendekatan ini.
quornian
3
Ketahuilah bahwa solusi tersebut tidak berfungsi untuk semua jenis sistem file. Misalnya tidak akan berfungsi untuk memeriksa apakah /proc/XXX/exetautan rusak. Untuk ini, gunakan test -e "$(readlink /proc/XXX/exe)".
qwertzguy
2
@Flimm find . -xtype lberarti "temukan semua symlink yang file target (akhir) -nya adalah symlink". Tetapi target akhir symlink tidak dapat symlink, jika tidak kita masih bisa mengikuti link dan itu bukan target akhir. Karena tidak ada symlink seperti itu, kita dapat mendefinisikannya sebagai sesuatu yang lain, yaitu symlink yang rusak.
lemah
2
@ JoóÁdám "yang hanya bisa menjadi tautan simbolis jika rusak". Berikan "tautan simbolis yang rusak" atau "file yang tidak ada" tipe individu, alih-alih kelebihan beban l, kurang membingungkan bagi saya.
lemah
3
Peringatan di bagian akhir berguna, tetapi perhatikan bahwa ini tidak berlaku untuk -Lperetasan tetapi untuk (secara membabi buta) menghapus symlink yang rusak secara umum.
Alois Mahdal
38

The symlinksperintah dari http://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gz dapat digunakan untuk mengidentifikasi symlink dengan berbagai karakteristik. Misalnya:

$ rm a
$ ln -s a b
$ symlinks .
dangling: /tmp/b -> a
Sam Morris
sumber
Apakah alat ini tersedia untuk osx?
qed
Sudahlah, sudah dikompilasi.
qed
2
Rupanya symlinkssudah diinstal sebelumnya di Fedora.
Daniel Jonsson
32

Seperti yang telah dikomentari rozcietrzewiacz, find -Ldapat memiliki konsekuensi yang tak terduga dari memperluas pencarian ke direktori yang terhubung, jadi bukan pendekatan yang optimal. Apa yang belum disebutkan siapa pun adalah itu

find /path/to/search -xtype l

adalah perintah yang lebih ringkas, dan identik secara logis

find /path/to/search -type l -xtype l

Tidak ada solusi yang disajikan sejauh ini akan mendeteksi symlink siklik, yang merupakan jenis kerusakan lainnya. pertanyaan ini membahas portabilitas. Untuk meringkas, cara portabel untuk menemukan tautan simbolis yang rusak, termasuk tautan siklik, adalah:

find /path/to/search -type l -exec test ! -e {} \; -print

Untuk detail lebih lanjut, lihat pertanyaan ini atau ynform.org . Tentu saja, sumber definitif untuk semua ini adalah dokumen findutils .

pooryorick
sumber
1
Short, consice, dan alamat find -Lperangkap serta link siklus. +1
Flimm
Bagus. Yang terakhir juga berfungsi pada MacOSX, sedangkan jawaban @ rozcietrzewiacz tidak.
neu242
1
@ neu242 Itu mungkin karena -xtypetidak ditentukan dalam POSIX dan memang jika Anda melihat find(1)di macOS itu -typetetapi tidak -xtype .
Pryftan
7

Saya percaya menambahkan -Lbendera ke perintah Anda akan memungkinkan Anda menyingkirkan grep:

$ find -L . -type l

http://www.commandlinefu.com/commands/view/8260/find-broken-symlinks

dari pria itu:

 -L      Cause the file information and file type (see stat(2)) returned 
         for each symbolic link to be those of the file referenced by the
         link, not the link itself. If the referenced file does not exist,
         the file information and type will be for the link itself.
kwarrick
sumber
19
Pada awalnya saya telah mengangkat ini, tetapi kemudian saya menyadari betapa berbahayanya itu. Sebelum Anda menggunakannya, silakan lihat jawaban saya !
rozcietrzewiacz
6

Jika Anda memerlukan perilaku berbeda apakah tautannya rusak atau siklik, Anda juga dapat menggunakan% Y dengan menemukan:

$ touch a
$ ln -s a b  # link to existing target
$ ln -s c d  # link to non-existing target
$ ln -s e e  # link to itself
$ find . -type l -exec test ! -e {} \; -printf '%Y %p\n' \
   | while read type link; do
         case "$type" in
         N) echo "do something with broken link $link" ;;
         L) echo "do something with cyclic link $link" ;;
         esac
      done
do something with broken link ./d
do something with cyclic link ./e

Contoh ini disalin dari pos ini (situs dihapus) .

Referensi

andy
sumber
Namun singkatan lain bagi mereka yang findperintah tidak mendukung xtypedapat diturunkan dari ini: find . type l -printf "%Y %p\n" | grep -w '^N'. Ketika andy mengalahkan saya untuk itu dengan ide (dasar) yang sama dalam naskahnya, saya enggan menuliskannya sebagai jawaban terpisah. :)
syntaxerror
2

Saya menggunakan ini untuk kasus saya dan berfungsi dengan baik, karena saya tahu direktori untuk mencari symlink yang rusak:

find -L $path -maxdepth 1 -type l

dan folder saya memang menyertakan tautan /usr/sharetetapi tidak melewatinya. Tautan lintas perangkat dan tautan yang valid untuk chroot, dll. Masih menjadi perangkap tetapi untuk kasus penggunaan saya cukup.

Iskren
sumber
2

Jawaban no-brainer sederhana, yang merupakan variasi pada versi OP. Terkadang, Anda hanya ingin sesuatu yang mudah diketik atau diingat:

find . | xargs file | grep -i "broken symbolic link"
trinth
sumber
1

find -L . -type l |xargs symlinks akan memberi Anda info apakah tautan ada atau tidak berdasarkan per foundfile.

Alex
sumber
1

Ini akan mencetak nama-nama symlink yang rusak di direktori saat ini.

for l in $(find . -type l); do cd $(dirname $l); if [ ! -e "$(readlink $(basename $l))" ]; then echo $l; fi; cd - > /dev/null; done

Bekerja di Bash. Tidak tahu tentang kerang lainnya.

conradkdotcom
sumber