Comment puis-je trouver des liens symboliques brisés

282

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 pas de distinction entre les liens qui vont quelque part et les liens qui ne vont pas.

Je suis en train de faire:

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

Mais je me demande quelles solutions alternatives existent.

gabe.
la source

Réponses:

351

Je suggère fortement de ne pas utiliser find -L cette tâche (voir l'explication ci-dessous). Voici d'autres moyens de le faire:

  • Si vous voulez utiliser une findméthode "pure ", elle devrait plutôt ressembler à ceci:

    find . -xtype l
    

    ( xtypeest un test effectué sur un lien déréférencé) Il peut ne pas être disponible dans toutes les versions de find. Mais il y a aussi d'autres options:

  • Vous pouvez également exécuter test -edepuis la findcommande:

    find . -type l ! -exec test -e {} \; -print
    
  • Même certains greptrucs pourraient être meilleurs (c'est-à-dire plus sûrs ) que find -L, mais pas exactement tels que présentés dans la question (qui grimpe dans 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
    

L' find -Lastuce citée par solo de commandlinefu a l' air sympa et hacky, mais elle comporte un piège très dangereux : tous les liens symboliques sont suivis. Considérons un 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 courez find -L . -type ldans ce répertoire, tous /usr/share/seront également recherchés (et cela peut prendre très longtemps) 1 . Pour une findcommande "insensible aux liens sortants", n'utilisez pas-L .


1 Cela peut sembler être un inconvénient mineur (la commande mettra "juste" longtemps à tout parcourir /usr/share) - mais peut avoir des conséquences plus graves. Par exemple, considérons 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 désignent que les lieux appropriés une fois que vous êtes entré dans le chroot. Je rappelle également que certains chargeurs de démarrage utilisaient des liens symboliques sous /bootcela 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 une find -Lcommande pour rechercher puis supprimer des liens symboliques rompus dans un répertoire inoffensif, vous risquez même de casser votre système ...

rozcietrzewiacz
la source
11
Je pense -type lest redondant puisque -xtype lfonctionnera comme -type lsur des non-liens. Donc, find -xtype lc'est probablement tout ce dont vous avez besoin. Merci pour cette approche.
Quornian
3
Sachez que ces solutions ne fonctionnent pas pour tous les types de systèmes de fichiers. Par exemple, cela ne fonctionnera pas pour vérifier si le /proc/XXX/exelien est cassé. Pour cela, utilisez test -e "$(readlink /proc/XXX/exe)".
Qwertzguy
2
@Flimm find . -xtype lsignifie "trouver tous les liens symboliques dont les fichiers cibles (ultimes) sont des liens symboliques". Mais la cible ultime d'un lien symbolique ne peut pas être un lien symbolique, sinon nous pouvons toujours suivre le lien et ce n'est pas la cible ultime. Comme il n’existe pas de lien symbolique, nous pouvons les définir comme autre chose, c’est-à-dire des liens symboliques rompus.
faible
2
@ JoóÁdám "qui ne peut être qu'un lien symbolique en cas de rupture". Donner à "lien symbolique brisé" ou "fichier non existant" un type individuel, au lieu de surcharger l, m'embrouille moins.
faible
3
L’avertissement à la fin est utile, mais notez que cela ne s’applique pas au -Lhack, mais plutôt à la suppression (à l’aveugle) de liens symboliques brisés en général.
Alois Mahdal
38

La symlinkscommande de http://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gz peut être utilisée pour identifier des liens symboliques présentant diverses caractéristiques. Par exemple:

$ rm a
$ ln -s a b
$ symlinks .
dangling: /tmp/b -> a
Sam Morris
la source
Cet outil est-il disponible pour osx?
Qed
Qu'à cela ne tienne, je l'ai compilé.
Qed
2
Apparemment, symlinksest pré-installé sur Fedora.
Daniel Jonsson
32

Comme l'a déjà commenté rozcietrzewiacz, le fait find -Ld'étendre la recherche à des annuaires liés par des liens symboliques peut avoir des conséquences inattendues. L'approche optimale n'est donc pas 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 constitue un autre type de rupture. cette question concerne la portabilité. Pour résumer, le moyen portable de trouver des liens symboliques brisés, y compris des liens cycliques, est:

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

Pour plus de détails, voir cette question ou ynform.org . Bien entendu, la source définitive de tout cela est la documentaton findutils .

pooryorick
la source
1
Court, consice et adresse le find -Lpiège ainsi que les liens cycliques. +1
Flimm
Agréable. Le dernier fonctionne également sur MacOSX, contrairement à la réponse de @ rozcietrzewiacz.
neu242
1
@ neu242 C'est probablement parce que ce -xtypen'est pas spécifié dans POSIX et bien si vous regardez find(1)dans macOS, c'est le cas -typemais pas -xtype .
Pryftan
7

Je pense que l'ajout du -Ldrapeau à votre commande vous permettra de vous débarrasser du 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.
Kwarrick
la source
19
Au début, j'ai voté pour cela, mais j'ai ensuite réalisé à quel point cela pouvait être dangereux . Avant de l' utiliser, s'il vous plaît jeter un oeil à ma réponse !
rozcietrzewiacz
6

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 ce message (site supprimé) .

Référence

Andy
la source
Une autre raccourci pour ceux dont la findcommande ne prend pas en charge xtypepeut être dérivé de ceci: find . type l -printf "%Y %p\n" | grep -w '^N'. Comme Andy m'a battu avec la même idée (de base) dans son script, j'étais réticent à l'écrire en tant que réponse séparée. :)
syntaxerror
2

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

find -L $path -maxdepth 1 -type l

et mon dossier contient un lien vers /usr/sharemais il ne le traverse pas. Les liens entre périphériques et ceux qui sont valables pour les chroots, etc. constituent toujours un piège, mais dans mon cas d'utilisation, cela suffit.

Iskren
la source
2

Une réponse simple, qui est une variation de la version de OP. Parfois, vous voulez juste quelque chose de facile à taper ou à retenir:

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

find -L . -type l |xargs symlinks vous indiquera si le lien existe ou non par fichier trouvé.

Alex
la source
1

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

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

Fonctionne à Bash. Je ne sais pas pour les autres coquilles.

Conradkdotcom
la source