Come posso trovare collegamenti simbolici rotti


282

Esiste un modo per trovare tutti i collegamenti simbolici che non indicano alcun punto?

find ./ -type l

mi darà tutti i collegamenti simbolici, ma non fa alcuna distinzione tra collegamenti che vanno da qualche parte e collegamenti che non lo fanno.

Attualmente sto facendo:

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

Ma mi chiedo quali soluzioni alternative esistano.

Risposte:


351

Consiglio vivamente di non utilizzare find -L per l'attività (vedi sotto per la spiegazione). Ecco alcuni altri modi per farlo:

  • Se vuoi usare un findmetodo "puro ", dovrebbe piuttosto apparire così:

    find . -xtype l
    

    ( xtypeè un test eseguito su un link non referenziato) findTuttavia, potrebbe non essere disponibile in tutte le versioni di . Ma ci sono anche altre opzioni:

  • Puoi anche eseguire test -edal findcomando:

    find . -type l ! -exec test -e {} \; -print
    
  • Anche qualche greptrucco potrebbe essere migliore (cioè più sicuro ) di find -L, ma non esattamente come quello presentato nella domanda (che si insinua in intere linee di output, compresi i nomi di file):

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

Il find -Ltrucco citato da solo da commandlinefu sembra carino e confuso, ma ha una trappola molto pericolosa : vengono seguiti tutti i collegamenti simbolici. Prendi in considerazione la directory con i contenuti presentati di seguito:

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

Se si esegue find -L . -type lin quella directory, anche tutti /usr/share/verrebbero cercati (e ciò potrebbe richiedere molto tempo) 1 . Per un findcomando "immune ai collegamenti in uscita", non utilizzare-L .


1 Questo può sembrare un piccolo inconveniente (il comando richiederà "solo" molto tempo per attraversare tutto /usr/share) - ma può avere conseguenze più gravi. Ad esempio, considera gli ambienti chroot: possono esistere in alcune sottodirectory del filesystem principale e contenere collegamenti simbolici a posizioni assolute. Questi collegamenti potrebbero sembrare non funzionanti per il sistema "esterno", perché indicano punti corretti solo dopo aver inserito il chroot. Ricordo anche che alcuni bootloader utilizzavano collegamenti simbolici /bootche avevano senso solo in una fase di avvio iniziale, quando la partizione di avvio era montata come /.

Quindi, se usi un find -Lcomando per trovare e quindi eliminare collegamenti simbolici rotti da una directory dall'aspetto innocuo, potresti persino rompere il tuo sistema ...


11
Penso che -type lsia ridondante poiché -xtype lfunzionerà come -type lsu non-link. Quindi find -xtype lè probabilmente tutto ciò di cui hai bisogno. Grazie per questo approccio.
Quornian,

3
Tenere presente che tali soluzioni non funzionano per tutti i tipi di file system. Ad esempio, non funzionerà per verificare se il /proc/XXX/execollegamento è interrotto. Per questo, usa test -e "$(readlink /proc/XXX/exe)".
qwertzguy,

2
@Flimm find . -xtype lsignifica "trova tutti i collegamenti simbolici i cui file di destinazione ( finali ) sono collegamenti simbolici". Ma l'obiettivo finale di un collegamento simbolico non può essere un collegamento simbolico, altrimenti possiamo ancora seguire il collegamento e non è l'obiettivo finale. Poiché non esistono tali collegamenti simbolici, possiamo definirli come qualcos'altro, ovvero collegamenti simbolici non funzionanti.
debole l'

2
@ JoóÁdám "che può essere solo un collegamento simbolico in caso di interruzione". Dare a "collegamento simbolico interrotto" o "file inesistente" un tipo individuale, invece di sovraccaricarlo l, è meno confuso per me.
debole il

3
L'avvertimento alla fine è utile, ma nota che questo non si applica -Lall'hacking ma piuttosto alla rimozione (cieca) di link simbolici rotti in generale.
Alois Mahdal,


32

Come rozcietrzewiacz ha già commentato, find -Lpuò avere conseguenze inaspettate sull'espansione della ricerca in directory con collegamenti simbolici, quindi non è l'approccio ottimale. Ciò che nessuno ha ancora menzionato è quello

find /path/to/search -xtype l

è il comando più conciso e logicamente identico a

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

Nessuna delle soluzioni presentate finora rileverà collegamenti simbolici ciclici, che è un altro tipo di rottura. questa domanda riguarda la portabilità. Riassumendo, il modo portatile per trovare collegamenti simbolici interrotti, inclusi collegamenti ciclici, è:

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

Per maggiori dettagli, vedi questa domanda o ynform.org . Naturalmente, la fonte definitiva di tutto ciò è la documentazione di Findutils .


1
Breve, consice e affronta la find -Ltrappola così come i collegamenti ciclici. +1
Flimm,

Bello. L'ultimo funziona anche su MacOSX, mentre la risposta di @ rozcietrzewiacz no.
neu242,

1
@ neu242 Questo è probabilmente perché -xtypenon è specificato in POSIX e in effetti se lo guardi find(1)in macOS lo ha -typema non lo è -xtype.
Pryftan,

7

Credo che l'aggiunta della -Lbandiera al tuo comando ti consentirà di sbarazzarti del grep:

$ find -L . -type l

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

dall'uomo:

 -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
All'inizio l'ho votato, ma poi ho capito quanto possa essere pericoloso . Prima di utilizzarlo, si prega di dare un'occhiata alla mia risposta !
rozcietrzewiacz,

6

Se hai bisogno di un comportamento diverso se il collegamento è interrotto o ciclico puoi anche usare% Y con 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

Questo esempio viene copiato da questo post (sito eliminato) .

Riferimento


Ancora un'altra scorciatoia per coloro il cui findcomando non supporta xtypepuò essere derivato da questo: find . type l -printf "%Y %p\n" | grep -w '^N'. Mentre andy mi ha battuto con la stessa idea (di base) nella sua sceneggiatura, ero riluttante a scriverla come risposta separata. :)
syntaxerror il

2

Lo uso per il mio caso e funziona abbastanza bene, poiché conosco la directory per cercare collegamenti simbolici non funzionanti:

find -L $path -maxdepth 1 -type l

e la mia cartella include un collegamento /usr/sharema non lo attraversa. I collegamenti tra dispositivi e quelli validi per chroot, ecc. Sono ancora una trappola ma per il mio caso d'uso è sufficiente.


2

Risposta semplice, che è una variante della versione di OP. A volte, vuoi solo qualcosa di facile da scrivere o da ricordare:

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

1

find -L . -type l |xargs symlinks ti fornirà informazioni sull'esistenza o meno del collegamento in base al file trovato.


1

Ciò stamperà i nomi dei collegamenti simbolici non funzionanti nella directory corrente.

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

Funziona in Bash. Non so di altre conchiglie.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.