我如何找到损坏的符号链接


281

有没有办法找到所有没有指向的符号链接?

find ./ -type l

会给我所有符号链接,但不会区分到某个地方的链接和没有链接的地方。

我目前正在做:

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

但我想知道还有哪些替代解决方案。

Answers:


351

我强烈建议使用find -L 的任务(见下文解释)。这是执行此操作的其他一些方法:

  • 如果要使用“纯find”方法,则应如下所示:

    find . -xtype l
    

    xtype是在取消引用的链接上执行的测试)find,但可能并非在所有版本中都可用。但是,还有其他选择:

  • 您还可以test -e从以下find命令中执行:

    find . -type l ! -exec test -e {} \; -print
    
  • 甚至有一些grep技巧可能比更好(即更安全find -L,但与问题中提出的完全不一样(它将在整个输出行中晃动,包括文件名):

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

solocommandlinefufind -L引用的技巧看起来不错而且很hacky,但是它有一个非常危险的陷阱:遵循所有符号链接。考虑目录,其内容如下所示:

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

如果您find -L . -type l在该目录中运行,则/usr/share/还将搜索所有内容(这可能需要很长时间)1对于find“不受传出链接影响” 的命令,请不要使用-L


1这看起来/usr/share有点不便(该命令将“花很长时间”遍历所有对象)–但可能会导致更严重的后果。例如,考虑chroot环境:它们可以存在于主文件系统的某些子目录中,并且包含指向绝对位置的符号链接。这些链接对于“外部”系统而言似乎是断开的,因为它们仅在您输入chroot后才指向正确的位置。我还记得,一些引导程序使用的符号链接/boot仅在初始引导阶段(引导分区安装为)才有意义/

因此,如果您使用find -L命令从看起来无害的目录中查找然后删除损坏的符号链接,甚至可能会破坏系统...


11
我认为这-type l是多余的,因为-xtype l它将-type l在非链接上运行。所以find -xtype l可能就是您所需要的。感谢您的这种方法。
quornian

3
请注意,这些解决方案不适用于所有文件系统类型。例如,它不适用于检查/proc/XXX/exe链接是否断开。为此,请使用test -e "$(readlink /proc/XXX/exe)"
qwertzguy

2
@Flimm的find . -xtype l意思是“找到所有(最终)目标文件是符号链接的符号链接”。但是符号链接的最终目标不能是符号链接,否则我们仍然可以跟随该链接,它不是最终目标。由于没有这样的符号链接,我们可以将它们定义为其他符号链接,即损坏的符号链接。
弱势

2
@JoóÁdám“这只能是一个符号链接,以防它损坏”。给“破碎的符号链接”或“不存在的文件”一个单独的类型,而不是重载l,对我来说就不那么混乱了。
弱势

3
最后的警告很有用,但请注意,这不适用于-L黑客攻击,而是(通常)一味地删除损坏的符号链接。
Alois Mahdal


32

正如rozcietrzewiacz所说,find -L将搜索扩展到符号链接目录可能会产生意想不到的结果,因此并不是最佳方法。还没有人提到

find /path/to/search -xtype l

是更简洁,逻辑上相同的命令

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

到目前为止提出的解决方案都无法检测到循环符号链接,这是另一种破坏方式。 这个问题解决了可移植性。总而言之,查找损坏的符号链接(包括循环链接)的可移植方法是:

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

有关更多详细信息,请参阅此问题ynform.org。当然,所有这些的最终来源是findutils documentaton


1
简短,简洁并解决find -L陷阱以及周期性链接。+1
Flimm 2014年

真好 最后一个也可以在MacOSX上运行,而@rozcietrzewiacz的回答没有。
neu242 '16

1
@ neu242因为很可能-xtype在POSIX没有指定,事实上,如果你看一下find(1)在MacOS上有-type,但不是 -xtype
Pryftan

7

我相信将-L标志添加到您的命令将使您摆脱grep:

$ find -L . -type l

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

从男人那里:

 -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
起初我对此表示赞同,但后来我意识到它可能是多么危险。在使用它之前,请先看看我的答案
rozcietrzewiacz 2012年

6

如果您需要其他行为(无论链接是断开还是循环的),也可以将%Y与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

此示例是从此帖子复制的(网站已删除)

参考


对于那些find不支持命令的人来说,还有另一个简写xtype可以从中得出:find . type l -printf "%Y %p\n" | grep -w '^N'。当安迪(Andy)在他的剧本中以相同(基本)的想法击败我时,我不愿意将其写为单独的答案。:)
语法错误

2

我将其用于我的情况,并且效果很好,因为我知道要查找损坏的符号链接的目录:

find -L $path -maxdepth 1 -type l

而且我的文件夹中确实包含一个指向的链接,/usr/share但它没有遍历它。跨设备链接以及对chroot有效的链接等仍然是一个陷阱,但对于我的用例而言,这已经足够了。


2

简单的答案,这是OP版本的变体。有时,您只想要一些易于输入或记住的内容:

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

1

find -L . -type l |xargs symlinks 将根据每个foundfile为您提供链接是否存在的信息。


1

这将在当前目录中打印出损坏的符号链接的名称。

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

在Bash中工作。不了解其他外壳。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.