Wie finde ich defekte Symlinks?

282

Gibt es eine Möglichkeit, alle symbolischen Links zu finden, die nicht auf etwas verweisen?

find ./ -type l

Gibt mir alle symbolischen Links, unterscheidet aber nicht zwischen Links, die irgendwo hingehen, und Links, die es nicht tun.

Ich mache gerade:

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

Aber ich frage mich, welche alternativen Lösungen existieren.

gabe.
quelle

Antworten:

351

Ich würde vorschlagen , stark nicht zu verwenden find -L für die Aufgabe (Erläuterung siehe unten). Hier sind einige andere Möglichkeiten, dies zu tun:

  • Wenn Sie eine "reine find" Methode verwenden möchten , sollte sie eher so aussehen:

    find . -xtype l
    

    ( xtypeIst ein Test auf einem dereferenzierte Link ausgeführt) Dies kann nicht in allen Versionen von zur Verfügung steht findallerdings. Es gibt aber auch andere Möglichkeiten:

  • Sie können auch test -eaus dem findBefehl ausführen :

    find . -type l ! -exec test -e {} \; -print
    
  • Sogar ein grepTrick könnte besser (dh sicherer ) sein als find -L, aber nicht genau wie in der Frage dargestellt (der ganze Ausgabezeilen, einschließlich Dateinamen, greift):

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

Der find -LTrick zitiert von Solo von commandlinefu sieht nett aus und hacky, aber es hat eine sehr gefährliche pitfall : Alle symbolischen Links gefolgt sind. Betrachten Sie das Verzeichnis mit den folgenden Inhalten:

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

Wenn Sie find -L . -type lin diesem Verzeichnis laufen , werden auch alle /usr/share/durchsucht (und das kann sehr lange dauern) 1 . Verwenden Sie für einen findBefehl, der "immun gegen ausgehende Links" ist, nicht-L .


1 Dies mag wie eine kleine Unannehmlichkeit aussehen (der Befehl wird "nur" lange brauchen, um alle zu durchlaufen /usr/share) - kann jedoch schwerwiegendere Konsequenzen haben. Betrachten Sie beispielsweise Chroot-Umgebungen: Sie können in einem Unterverzeichnis des Hauptdateisystems vorhanden sein und Symlinks zu absoluten Positionen enthalten. Diese Verknüpfungen scheinen für das "äußere" System defekt zu sein, da sie nur dann auf richtige Stellen verweisen, wenn Sie die Chroot betreten haben. Ich erinnere mich auch, dass einige Bootloader Symlinks verwendeten /boot, die nur in einer anfänglichen Bootphase Sinn machten, als die Bootpartition als gemountet wurde /.

Wenn Sie also einen find -LBefehl verwenden, um defekte Symlinks in einem harmlos aussehenden Verzeichnis zu suchen und dann zu löschen, können Sie sogar Ihr System beschädigen ...

rozcietrzewiacz
quelle
11
Ich halte -type ldas für überflüssig -xtype l, da -type lbei Nicht-Links so verfahren wird. Also find -xtype list wahrscheinlich alles was Sie brauchen. Danke für diesen Ansatz.
Quornian
3
Beachten Sie, dass diese Lösungen nicht für alle Dateisystemtypen funktionieren. Zum Beispiel funktioniert es nicht, um zu überprüfen, ob die /proc/XXX/exeVerbindung unterbrochen ist. Verwenden Sie dazu test -e "$(readlink /proc/XXX/exe)".
Qwertzguy
2
@Flimm find . -xtype lbedeutet "Finde alle Symlinks, deren (ultimative) Zieldateien Symlinks sind". Das endgültige Ziel eines Symlinks kann jedoch kein Symlink sein. Andernfalls können wir dem Link weiterhin folgen und es ist nicht das endgültige Ziel. Da es keine solchen Symlinks gibt, können wir sie als etwas anderes definieren, dh als defekte Symlinks.
schwache
2
@ JoóÁdám "Das kann nur ein symbolischer Link sein, wenn es kaputt ist". Geben Sie "broken symbolic link" oder "non exist file" einen individuellen Typ, anstatt ihn zu überladen l, ist für mich weniger verwirrend.
schwache
3
Die Warnung am Ende ist nützlich, aber beachten Sie, dass dies nicht für den -LHack gilt, sondern für das (blinde) Entfernen defekter Symlinks im Allgemeinen.
Alois Mahdal
38

Der symlinksBefehl von http://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gz kann verwendet werden, um Symlinks mit einer Vielzahl von Merkmalen zu identifizieren. Zum Beispiel:

$ rm a
$ ln -s a b
$ symlinks .
dangling: /tmp/b -> a
Sam Morris
quelle
Ist dieses Tool für osx verfügbar?
qed
Egal, habe es zusammengestellt.
Qed
2
Anscheinend symlinksist auf Fedora vorinstalliert.
Daniel Jonsson
32

Wie rozcietrzewiacz bereits kommentiert hat, find -Lkann die Ausweitung der Suche auf verknüpfte Verzeichnisse unerwartete Folgen haben, ist also nicht der optimale Ansatz. Was noch niemand erwähnt hat, ist das

find /path/to/search -xtype l

ist der prägnantere und logisch identische Befehl zu

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

Keine der bisher vorgestellten Lösungen erkennt zyklische Symlinks, was eine andere Art von Bruch darstellt. Diese Frage befasst sich mit der Portabilität. Zusammenfassend lässt sich sagen, dass die Suche nach defekten symbolischen Links, einschließlich zyklischer Links, portabel ist:

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

Weitere Einzelheiten finden Sie in dieser Frage oder auf ynform.org . Die endgültige Quelle für all dies ist natürlich die Dokumentation der Fundstücke .

Pooryorick
quelle
1
Kurz und bündig, spricht die find -LFallstricke und zyklische Links an. +1
Flimm
Nett. Der letzte funktioniert auch unter MacOSX, die Antwort von @ rozcietrzewiacz hingegen nicht.
Neu242
1
@ neu242 Das liegt wohl daran, dass -xtypees in POSIX nicht spezifiziert ist und wenn man es find(1)in macOS anschaut hat es das -typeaber nicht -xtype .
Pryftan,
7

Ich glaube, das Hinzufügen der -LFlagge zu Ihrem Befehl ermöglicht es Ihnen, das grep loszuwerden:

$ find -L . -type l

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

vom mann:

 -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
quelle
19
Zuerst habe ich das positiv bewertet, aber dann habe ich gemerkt, wie gefährlich es sein kann. Bevor Sie es benutzen, schauen Sie sich bitte meine Antwort an !
rozcietrzewiacz
6

Wenn Sie ein anderes Verhalten benötigen, unabhängig davon, ob die Verknüpfung unterbrochen oder zyklisch ist, können Sie auch% Y mit find verwenden:

$ 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

Dieses Beispiel wurde aus diesem Beitrag kopiert (Site gelöscht) .

Referenz

Andy
quelle
Noch eine andere Abkürzung für diejenigen , deren findBefehl unterstützt nicht xtypedaraus abgeleitet werden kann: find . type l -printf "%Y %p\n" | grep -w '^N'. Da Andy mich mit der gleichen (grundlegenden) Idee in seinem Drehbuch verprügelte, wollte ich es nicht als separate Antwort schreiben. :)
Syntaxfehler
2

Ich benutze dies für meinen Fall und es funktioniert ziemlich gut, da ich das Verzeichnis kenne, um nach defekten Symlinks zu suchen:

find -L $path -maxdepth 1 -type l

und mein Ordner enthält einen Link zu /usr/share, überquert ihn jedoch nicht. Geräteübergreifende Links und solche, die für Chroots usw. gültig sind, sind immer noch eine Falle, aber für meinen Anwendungsfall ist es ausreichend.

Iskren
quelle
2

Einfache, einfache Antwort, eine Variation der OP-Version. Manchmal möchten Sie einfach nur etwas einfach zu tippen oder sich zu erinnern:

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

find -L . -type l |xargs symlinks gibt Ihnen Informationen darüber, ob der Link vorhanden ist oder nicht, und zwar auf der Basis der gefundenen Dateien.

Alex
quelle
1

Dadurch werden die Namen defekter Symlinks im aktuellen Verzeichnis ausgedruckt.

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

Arbeitet in Bash. Ich weiß nichts über andere Muscheln.

conradkdotcom
quelle