Jak mogę znaleźć zepsute dowiązania symboliczne

282

Czy istnieje sposób na znalezienie wszystkich dowiązań symbolicznych, które nigdzie nie wskazują?

find ./ -type l

poda mi wszystkie dowiązania symboliczne, ale nie czyni rozróżnienia między linkami, które gdzieś idą, a linkami, które nie.

Obecnie robię:

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

Ale zastanawiam się, jakie istnieją alternatywne rozwiązania.

Gabe.
źródło

Odpowiedzi:

351

Chciałbym zdecydowanie sugerują, nie używać find -L do tego zadania (patrz poniżej dla wyjaśnienia). Oto kilka innych sposobów, aby to zrobić:

  • Jeśli chcesz użyć findmetody „czystej ”, powinna ona wyglądać następująco:

    find . -xtype l
    

    ( xtypejest to test przeprowadzony na dereferencyjnym łączu). Może to nie być dostępne we wszystkich wersjach find. Ale są też inne opcje:

  • Można również exec test -ez poziomu findpolecenia:

    find . -type l ! -exec test -e {} \; -print
    
  • Nawet jakaś grepsztuczka mogłaby być lepsza (tj. Bezpieczniejsza ) niż find -L, ale nie dokładnie taka jak przedstawiona w pytaniu (która grepuje w całych liniach wyjściowych, w tym nazwach plików):

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

find -LTrik cytowany przez solówki z commandlinefu wygląda ładnie i hacky, ale ma jedną bardzo niebezpieczne pułapki : Wszystkie dowiązania są przestrzegane. Rozważ katalog z zawartością przedstawioną poniżej:

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

Jeśli uruchomisz find -L . -type lten katalog, /usr/share/przeszukane zostaną również wszystkie (i może to potrwać naprawdę długo) 1 . W przypadku findpolecenia „odpornego na linki wychodzące” nie używaj-L .


1 Może to wyglądać na niewielką niedogodność (polecenie „po prostu” zajmie całe przejście /usr/share), ale może mieć poważniejsze konsekwencje. Rozważmy na przykład środowiska chroot: mogą istnieć w pewnym podkatalogu głównego systemu plików i zawierać dowiązania symboliczne do absolutnych lokalizacji. Te linki mogą wydawać się zepsute w systemie „zewnętrznym”, ponieważ wskazują na właściwe miejsca dopiero po wejściu do chroot. Pamiętam również, że niektóre bootloadery używały dowiązań symbolicznych w /boottym sensie tylko w początkowej fazie rozruchu, kiedy partycja rozruchowa została zamontowana jako /.

Jeśli więc użyjesz find -Lpolecenia, aby znaleźć, a następnie usunąć uszkodzone dowiązania symboliczne z jakiegoś nieszkodliwego katalogu, możesz nawet uszkodzić system ...

rozcietrzewiacz
źródło
11
Myślę, że -type ljest zbędny, ponieważ -xtype lbędzie działał jak -type lna nie-linkach. Więc find -xtype lto chyba wszystko, czego potrzebujemy. Dzięki za to podejście.
kwornian
3
Należy pamiętać, że te rozwiązania nie działają dla wszystkich typów systemów plików. Na przykład nie będzie działać sprawdzanie, czy /proc/XXX/exelink nie jest uszkodzony. W tym celu użyj test -e "$(readlink /proc/XXX/exe)".
qwertzguy
2
@Flimm find . -xtype loznacza „znajdź wszystkie dowiązania symboliczne, których (docelowymi) plikami docelowymi są dowiązania symboliczne”. Ale ostatecznym celem dowiązania symbolicznego nie może być dowiązanie symboliczne, w przeciwnym razie nadal możemy podążać za dowiązaniem i nie jest to cel ostateczny. Ponieważ nie ma takich dowiązań symbolicznych, możemy zdefiniować je jako coś innego, tj. Zepsute dowiązania symboliczne.
słaby
2
@ JoóÁdám „który może być tylko dowiązaniem symbolicznym w przypadku jego uszkodzenia”. Daj „uszkodzonemu dowiązaniu symbolicznemu” lub „nieistniejącemu plikowi” indywidualny typ, zamiast przeciążania l, jest dla mnie mniej mylące.
słaby
3
Ostrzeżenie na końcu jest przydatne, ale pamiętaj, że nie dotyczy to -Lhacka, ale raczej (ślepo) usuwania zepsutych dowiązań symbolicznych w ogóle.
Alois Mahdal
38

symlinksPolecenie od http://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gz mogą być wykorzystane do identyfikacji dowiązania z różnych cechach. Na przykład:

$ rm a
$ ln -s a b
$ symlinks .
dangling: /tmp/b -> a
Sam Morris
źródło
Czy to narzędzie jest dostępne dla systemu OSX?
QED
Nieważne, skompilowałem to.
qed
2
Najwyraźniej symlinksjest wstępnie zainstalowany na Fedorze.
Daniel Jonsson,
32

Jak już komentował rozcietrzewiacz, find -Lmoże mieć nieoczekiwaną konsekwencję rozszerzenia wyszukiwania na katalogi dowiązane, więc nie jest to optymalne podejście. Nikt jeszcze o tym nie wspominał

find /path/to/search -xtype l

to bardziej zwięzłe i logicznie identyczne polecenie

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

Żadne z przedstawionych dotychczas rozwiązań nie wykryje cyklicznych dowiązań symbolicznych, co jest innym rodzajem uszkodzenia. to pytanie dotyczy przenośności. Podsumowując, przenośnym sposobem na znalezienie uszkodzonych dowiązań symbolicznych, w tym łączy cyklicznych, jest:

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

Aby uzyskać więcej informacji, zobacz to pytanie lub ynform.org . Oczywiście ostatecznym źródłem tego wszystkiego jest dokumentacja findutils .

pooryorick
źródło
1
Krótko, sumiennie i zajmuje się pułapką, a find -Ltakże linkami cyklicznymi. +1
Flimm
Miły. Ten ostatni działa również na MacOSX, a odpowiedź @ rozcietrzewiacz nie.
neu242,
1
@ neu242 Jest to prawdopodobne, ponieważ -xtypenie jest określone w POSIX i rzeczywiście, jeśli spojrzysz na find(1)macOS, to ma, -typeale nie ma -xtype .
Pryftan
7

Wierzę, że dodanie -Lflagi do twojego polecenia pozwoli ci pozbyć się grep:

$ find -L . -type l

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

od mężczyzny:

 -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
źródło
19
Na początku głosowałem za tym, ale potem zdałem sobie sprawę, jak niebezpieczne może być. Zanim go używać, proszę spojrzeć na moją odpowiedź !
rozcietrzewiacz
6

Jeśli potrzebujesz innego zachowania, niezależnie od tego, czy link jest zepsuty czy cykliczny, możesz również użyć% Y z funkcją 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

Ten przykład został skopiowany z tego postu (witryna usunięta) .

Odniesienie

andy
źródło
Jeszcze innym skrótem dla tych, których findkomenda nie obsługuje xtypemogą pochodzić z tego: find . type l -printf "%Y %p\n" | grep -w '^N'. Kiedy Andy pobił mnie tym samym (podstawowym) pomysłem w swoim skrypcie, niechętnie pisałem go jako osobną odpowiedź. :)
syntaxerror
2

Używam tego do mojego przypadku i działa całkiem dobrze, ponieważ znam katalog do wyszukiwania uszkodzonych dowiązań symbolicznych:

find -L $path -maxdepth 1 -type l

a mój folder zawiera link do, /usr/shareale go nie przechodzi. Łącza między urządzeniami i te, które są ważne dla chrootów itp., Wciąż stanowią pułapkę, ale w moim przypadku jest wystarczająca.

Iskren
źródło
2

Prosta odpowiedź bez zastanowienia, która jest odmianą wersji OP. Czasami chcesz po prostu coś łatwego do wpisania lub zapamiętania:

find . | xargs file | grep -i "broken symbolic link"
trinth
źródło
1

find -L . -type l |xargs symlinks poda informacje, czy link istnieje, czy nie, na podstawie znalezionego pliku.

Alex
źródło
1

Spowoduje to wydrukowanie nazw uszkodzonych dowiązań symbolicznych w bieżącym katalogu.

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

Działa w Bash. Nie wiem o innych pociskach.

conradkdotcom
źródło