Como posso encontrar links simbólicos quebrados


282

Existe uma maneira de encontrar todos os links simbólicos que não apontam para nada?

find ./ -type l

vai me dar todos os links simbólicos, mas não faz distinção entre links que vão a algum lugar e links que não.

Atualmente estou fazendo:

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

Mas estou me perguntando que soluções alternativas existem.

Respostas:


351

Eu sugiro fortemente não usar find -L para a tarefa (veja abaixo para explicação). Aqui estão algumas outras maneiras de fazer isso:

  • Se você deseja usar um findmétodo " puro ", deve parecer com o seguinte:

    find . -xtype l
    

    ( xtypeé um teste realizado em um link não referenciado). Isso pode não estar disponível em todas as versões de find. Mas existem outras opções também:

  • Você também pode executar test -ede dentro do findcomando:

    find . -type l ! -exec test -e {} \; -print
    
  • Mesmo algum greptruque poderia ser melhor (ou seja, mais seguro ) do que find -L, mas não exatamente como o apresentado na pergunta (que aparece em linhas de saída inteiras, incluindo nomes de arquivos):

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

O find -Ltruque citado por solo do commandlinefu parece bom e hacky, mas tem uma armadilha muito perigosa : todos os links simbólicos são seguidos. Considere o diretório com o conteúdo apresentado abaixo:

$ 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 você executar find -L . -type lnesse diretório, todos /usr/share/também serão pesquisados ​​(e isso pode levar muito tempo) 1 . Para um findcomando "imune a links de saída", não use-L .


1 Isso pode parecer um pequeno inconveniente (o comando "levará" muito tempo para percorrer tudo /usr/share) - mas pode ter consequências mais graves. Por exemplo, considere ambientes chroot: eles podem existir em algum subdiretório do sistema de arquivos principal e conter links simbólicos para locais absolutos. Esses links podem parecer quebrados para o sistema "externo", porque eles só apontam para lugares apropriados quando você entra no chroot. Lembro-me também de que algum carregador de inicialização usava links simbólicos sob /bootesse sentido apenas em uma fase inicial de inicialização, quando a partição de inicialização foi montada como /.

Portanto, se você usar um find -Lcomando para encontrar e excluir links simbólicos quebrados de algum diretório com aparência inofensiva, poderá até quebrar seu sistema ...


11
Eu acho que -type lé redundante, uma vez que -xtype lirá operar como -type lem não-links. Então, find -xtype lé provavelmente tudo que você precisa. Obrigado por esta abordagem.
quornian

3
Esteja ciente de que essas soluções não funcionam para todos os tipos de sistemas de arquivos. Por exemplo, não funcionará para verificar se o /proc/XXX/exelink está quebrado. Para isso, use test -e "$(readlink /proc/XXX/exe)".
Qwertzguy

2
@Flimm find . -xtype lsignifica "encontre todos os links simbólicos cujos arquivos de destino (finais) são links simbólicos". Mas o destino final de um link simbólico não pode ser um link simbólico; caso contrário, ainda podemos seguir o link e este não é o destino final. Como não existem links simbólicos, podemos defini-los como outra coisa, ou seja, links simbólicos quebrados.
weakish

2
@ JoóÁdám ", que só pode ser um link simbólico se estiver quebrado". Dar a "link simbólico quebrado" ou "arquivo não existente" um tipo individual, em vez de sobrecarregar l, é menos confuso para mim.
weakish

3
O aviso no final é útil, mas observe que isso não se aplica ao -Lhack, mas sim à remoção (cega) de links simbólicos quebrados em geral.
Alois Mahdal


32

Como o rozcietrzewiacz já comentou, find -Lpode ter consequências inesperadas ao expandir a pesquisa em diretórios com links simbólicos, portanto, não é a abordagem ideal. O que ninguém mencionou ainda é que

find /path/to/search -xtype l

é o comando mais conciso e logicamente idêntico ao

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

Nenhuma das soluções apresentadas até agora detectará links simbólicos cíclicos, que é outro tipo de quebra. Esta pergunta trata da portabilidade. Para resumir, a maneira portátil de encontrar links simbólicos quebrados, incluindo links cíclicos, é:

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

Para mais detalhes, consulte esta pergunta ou ynform.org . Obviamente, a fonte definitiva para tudo isso é a documentação do findutils .


1
Curto, consice e aborda a find -Larmadilha, bem como links cíclicos. +1
Flimm,

Agradável. O último também funciona no MacOSX, enquanto a resposta de @ rozcietrzewiacz não.
Neu242

1
@ neu242 Isso é provavelmente porque -xtypenão é especificado no POSIX e de fato se você olhar para find(1)no MacOS ele tem -type, mas não -xtype .
Pryftan

7

Eu acredito que adicionar a -Lflag ao seu comando permitirá que você se livre do grep:

$ find -L . -type l

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

do homem:

 -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
No começo eu votei isso de novo, mas depois percebi o quão perigoso pode ser. Antes de usá-lo, por favor, ter um olhar para a minha resposta !
Rozcietrzewiacz

6

Se você precisar de um comportamento diferente, independentemente de o link estar quebrado ou cíclico, também poderá usar% Y com o comando 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

Este exemplo é copiado desta postagem (site excluído) .

Referência


Ainda um outro atalho para aqueles cujo findcomando não suporta xtypepode ser derivada a partir desta: find . type l -printf "%Y %p\n" | grep -w '^N'. Como Andy me abordou com a mesma idéia (básica) em seu roteiro, fiquei relutante em escrevê-lo como resposta separada. :)
syntaxerror

2

Eu uso isso para o meu caso e funciona muito bem, pois conheço o diretório para procurar links simbólicos quebrados:

find -L $path -maxdepth 1 -type l

e minha pasta inclui um link para, /usr/sharemas não o atravessa. Links entre dispositivos e aqueles que são válidos para chroots etc. ainda são uma armadilha, mas para o meu caso de uso é suficiente.


2

Resposta simples e simples, que é uma variação da versão do OP. Às vezes, você só quer algo fácil de digitar ou lembrar:

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

1

find -L . -type l |xargs symlinks fornecerá informações se o link existe ou não, por arquivo encontrado.


1

Isso imprimirá os nomes dos links simbólicos quebrados no diretório atual.

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

Trabalha em Bash. Não conheço outras conchas.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.