web-dev-qa-db-fra.com

Comment trouver des liens symboliques brisés

Existe-t-il un moyen de trouver tous les liens symboliques qui ne pointent nulle part?

find ./ -type l

me donnera tous les liens symboliques, mais ne fait aucune distinction entre les liens qui vont quelque part et ceux qui ne le font pas.

Je fais actuellement:

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

Mais je me demande quelles solutions alternatives existent.

304
gabe.

Je suggère fortement de ne pas utiliser find -L pour la tâche (voir ci-dessous pour des explications). Voici d'autres façons de procéder:

  • Si vous souhaitez utiliser une méthode "pure find", elle devrait plutôt ressembler à ceci:

    find . -xtype l
    

    (xtype est un test effectué sur un lien déréférencé) Ceci peut ne pas être disponible dans toutes les versions de find, bien que. Mais il existe également d'autres options:

  • Vous pouvez également exécuter test -e depuis la commande find:

    find . -type l ! -exec test -e {} \; -print
    
  • Même une astuce grep pourrait être meilleure (c'est-à-dire plus sûr) que find -L, mais pas exactement tel que présenté dans la question (qui est perceptible sur des lignes de sortie entières, y compris les noms de fichiers):

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

Le find -L astuce citée par solo de commandlinef a l'air sympa et hacky, mais elle a un piège très dangereux : Tous les liens symboliques sont suivis. Considérez le répertoire avec le contenu présenté ci-dessous:

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

Si vous exécutez find -L . -type l dans ce répertoire, tous /usr/share/ serait également recherché (et cela peut prendre très longtemps)1. Pour une commande find "à l'abri des liens sortants", n'utilisez pas -L.


1 Cela peut ressembler à un inconvénient mineur (la commande prendra "juste" beaucoup de temps pour parcourir tous les /usr/share) - mais peut avoir des conséquences plus graves. Par exemple, considérez les environnements chroot: ils peuvent exister dans certains sous-répertoires du système de fichiers principal et contenir des liens symboliques vers des emplacements absolus. Ces liens peuvent sembler rompus pour le système "extérieur", car ils ne pointent vers des emplacements appropriés qu'une fois que vous êtes entré dans le chroot. Je me souviens également que certains chargeurs de démarrage utilisaient des liens symboliques sous /boot qui n'avait de sens que dans une phase de démarrage initiale, lorsque la partition de démarrage était montée en tant que /.

Donc, si vous utilisez un find -L commande pour rechercher puis supprimer les liens symboliques cassés d'un répertoire d'aspect inoffensif, vous pourriez même casser votre système ...

380
rozcietrzewiacz

La commande symlinks de http://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gz peut être utilisée pour identifier les liens symboliques avec une variété des caractéristiques. Par exemple:

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

Comme l'a déjà dit rozcietrzewiacz, find -L peut avoir des conséquences inattendues en étendant la recherche aux répertoires liés par des liens symboliques, ce n'est donc pas l'approche optimale. Ce que personne n'a encore mentionné, c'est que

find /path/to/search -xtype l

est la commande la plus concise et logiquement identique à

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

Aucune des solutions présentées jusqu'à présent ne détectera de liens symboliques cycliques, ce qui est un autre type de rupture. cette question traite de la portabilité. Pour résumer, la façon portable de trouver des liens symboliques rompus, y compris des liens cycliques, est la suivante:

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

Pour plus de détails, voir cette question ou ynform.org . Bien sûr, la source définitive de tout cela est le documentation de findutils .

33
pooryorick

Je crois que l'ajout de -L le drapeau de votre commande vous permettra de vous débarrasser de la grep:

$ find -L . -type l

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

de l'homme:

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

Si vous avez besoin d'un comportement différent, que le lien soit rompu ou cyclique, vous pouvez également utiliser% Y avec 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

Cet exemple est copié de cet article (site supprimé) .

Référence

7
andy

Réponse simple et évidente, qui est une variante de la version OP. Parfois, vous voulez juste quelque chose de facile à taper ou à retenir:

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

Ou, si vous devez gérer des terminateurs NULL:

find . -print0 | xargs -0 file | grep -i "broken symbolic link"
3
trinth

J'utilise ceci pour mon cas et cela fonctionne assez bien, car je connais le répertoire pour rechercher les liens symboliques cassés:

find -L $path -maxdepth 1 -type l

et mon dossier contient un lien vers /usr/share mais il ne le traverse pas. Les liens inter-appareils et ceux qui sont valides pour les chroots, etc. sont toujours un piège mais pour mon cas d'utilisation, c'est suffisant.

2
Iskren

Pour les utilisateurs de zsh:

rm -v **/*(-@)

from guide de l'utilisateur zsh (recherchez broken symlinks)

2
murlakatamenka

find -L . -type l |xargs symlinks vous donnera des informations sur l'existence ou non du lien par fichier trouvé.

1
Alex

Cela affichera les noms des liens symboliques rompus dans le répertoire courant.

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

Fonctionne dans Bash. Je ne sais pas pour les autres obus.

1
conradkleinespel