Як знайти зламані символьні посилання


282

Чи є спосіб знайти всі символічні посилання, які ні на що не вказують?

find ./ -type l

дасть мені всі символічні посилання, але не робить різниці між посиланнями, які кудись переходять, і посиланнями, які не мають.

Я зараз роблю:

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

Але мені цікаво, які альтернативні рішення існують.

Відповіді:


351

Я настійно пропоную не використовувати find -L для завдання (пояснення див. Нижче). Ось кілька інших способів зробити це:

  • Якщо ви хочете використовувати "чистий find" метод, він повинен виглядати так:

    find . -xtype l
    

    ( xtypeце тест, виконаний за відміненою посиланням). Однак це може бути доступне не у всіх версіях find. Але є й інші варіанти:

  • Ви також можете виконати test -eз findкоманди:

    find . -type l ! -exec test -e {} \; -print
    
  • Навіть якась grepхитрість може бути кращою (тобто, більш безпечною ), ніж find -L, але не зовсім такою, як це представлено у запитанні (яка відображається у всіх вихідних рядках, включаючи назви файлів):

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

find -LТрюк цитований по соло з commandlinefu виглядає красиво і Hacky, але у нього є один дуже небезпечна пастка : Всі аліаси слідують. Розгляньте каталог із вмістом, представленим нижче:

$ 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/

Якщо ви запускаєтесь find -L . -type lу цьому каталозі, усі /usr/share/також будуть шукатись (і це може зайняти дуже довго) 1 . Не використовуйте findкоманду, яка не захищена від вихідних посилань-L .


1 Це може виглядати як незначна незручність (команда "просто" займе багато часу, щоб об'їхати всі /usr/share), але може мати більш серйозні наслідки. Наприклад, розглянемо середовища chroot: Вони можуть існувати в якомусь підкаталозі основної файлової системи і містити посилання на абсолютні місця. Ці посилання можуть здаватися розірваними для "зовнішньої" системи, оскільки вони вказують на належні місця лише після того, як ви вступили в chroot. Я також пам'ятаю, що деякі завантажувачі використовували символьні посилання під /bootцим лише сенсом на початковій фазі завантаження, коли розділ завантаження був змонтований як /.

Отже, якщо ви використовуєте find -Lкоманду для пошуку, а потім видалення зламаних символьних посилань з якогось нешкідливого вигляду каталогу, ви навіть можете зламати вашу систему ...


11
Я думаю, що -type lце зайве, оскільки -xtype lбуде працювати як -type lна не-посиланнях. Так що find -xtype l, мабуть, все, що вам потрібно. Дякую за такий підхід.
курінь

3
Майте на увазі, що ці рішення працюють не для всіх типів файлової системи. Наприклад, він не буде працювати для перевірки, чи /proc/XXX/exeне порушено посилання. Для цього використовуйте test -e "$(readlink /proc/XXX/exe)".
qwertzguy

2
@Flimm find . -xtype lозначає "знайти всі символьні посилання, чиї (кінцеві) цільові файли є посиланнями". Але кінцева ціль символьного посилання не може бути символьною ланкою, інакше ми все одно можемо перейти за посиланням, і це не кінцева ціль. Оскільки таких символьних посилань немає, ми можемо визначити їх як щось інше, тобто розбиту символіку.
слабкий

2
@ JoóÁdám, "яка може бути лише символічним посиланням у випадку, якщо вона порушена". Надання "розірваному символічному посиланню" або "неіснуючому файлу" індивідуального типу, замість перевантаження l, для мене менш заплутане.
слабкий

3
Попередження в кінці корисно, але зауважте, що це стосується не -Lзламаного, а скоріше (сліпого) видалення зламаних символьних посилань.
Алоїс Магдал

38

symlinksКоманда з http://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gz може бути використана для ідентифікації симлінк з різними характеристиками. Наприклад:

$ rm a
$ ln -s a b
$ symlinks .
dangling: /tmp/b -> a

Чи доступний цей інструмент для OSX?
qed

Неважливо, склав це.
qed

2
Мабуть symlinks, попередньо встановлено на Fedora.
Даніель Джонсон

32

Як уже прокоментував rozcietrzewiacz, це find -Lможе мати несподівані наслідки розширення пошуку в пов'язаних каталогах, тому не є оптимальним підходом. Що ще ніхто не згадував, це те

find /path/to/search -xtype l

- це більш коротка та логічно ідентична команда

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

Жодне з представлених на сьогодні рішень не виявить циклічних посилань, що є ще одним типом поломки. це питання стосується портативності. Підсумовуючи, портативний спосіб пошуку порушених символьних посилань, включаючи циклічні посилання, є:

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

Більш детально див. Це питання або ynform.org . Звичайно, остаточним джерелом для всього цього є документальний фільм .


1
Коротка, конспіративна і вирішує проблему, find -Lа також циклічні посилання. +1
Flimm

Приємно. Останній працює також і на MacOSX, тоді як відповідь @ rozcietrzewiacz не відповів.
neu242

1
@ neu242 Це, швидше за -xtypeвсе, не вказано в POSIX, і якщо ви дивитесь find(1)у macOS, він має, -typeале ні -xtype .
Прифтан

7

Я вважаю, що додавання -Lпрапора до вашої команди дозволить вам позбутися від грепу:

$ find -L . -type l

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

від людини:

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

19
Спочатку я підтримав це, але потім зрозумів, наскільки це небезпечно . Перш ніж використовувати його, будь ласка , подивіться на мою відповідь !
rozcietrzewiacz

6

Якщо вам потрібна інша поведінка, розірвана чи циклічна посилання, ви також можете використовувати% Y з find:

$ 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

Цей приклад скопійовано з цієї публікації (сайт видалений) .

Довідково


Ще один скорочений варіант для тих , чия findкоманда не підтримує xtypeможе бути отримана з цього: find . type l -printf "%Y %p\n" | grep -w '^N'. Оскільки Енді бив мене з ним такою ж (основною) ідеєю в його сценарії, я не хотів писати це як окрему відповідь. :)
syntaxerror

2

Я використовую це для свого випадку, і він працює досить добре, оскільки я знаю, що каталог шукає зламані символьні посилання:

find -L $path -maxdepth 1 -type l

і моя папка містить посилання на, /usr/shareале воно не проходить її. Перехресні посилання на пристрої та ті, які є дійсними для chroots і т. Д., Як і раніше, залишаються непростими, але для мого використання цього достатньо.


2

Проста відповідь, яка не вимагає, що є варіантом версії ОП. Іноді просто хочеться щось легко набрати або запам'ятати:

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

1

find -L . -type l |xargs symlinks дасть вам інформацію про те, чи існує посилання на основі знайденого файлу чи ні.


1

Це дозволить роздрукувати імена зламаних символьних посилань у поточному каталозі.

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

Працює в Баші. Не знайте про інші снаряди.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.