如何找到损坏的符号链接

gab*_*be. 352 shell find symlink

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

find ./ -type l
Run Code Online (Sandbox Code Playgroud)

会给我所有的符号链接,但不区分去某处的链接和不去某处的链接。

我目前正在做:

find ./ -type l -exec file {} \; | grep broken
Run Code Online (Sandbox Code Playgroud)

但我想知道存在哪些替代解决方案。

roz*_*acz 449

我强烈建议以使用find -L 的任务(见下文解释)。这里有一些其他方法可以做到这一点:

  • 如果你想使用“纯find”方法,它应该看起来像这样:

    find . -xtype l
    
    Run Code Online (Sandbox Code Playgroud)

    xtype是在取消引用的链接上执行的测试)但这可能不适用于 的所有版本find。但也有其他选择:

  • 您还可以test -efind命令中执行:

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

     find . -type l -exec sh -c 'file -b "$1" | grep -q ^broken' sh {} \; -print
    
    Run Code Online (Sandbox Code Playgroud)

来自commandlinefu的 solofind -L引用的技巧看起来不错,但它有一个非常危险的陷阱:遵循所有符号链接。考虑包含以下内容的目录:

$ 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/
Run Code Online (Sandbox Code Playgroud)

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


1这可能看起来像一个小不便(命令将“只是”需要很长时间才能遍历所有/usr/share)——但可能会产生更严重的后果。例如,考虑 chroot 环境:它们可以存在于主文件系统的某个子目录中,并包含指向绝对位置的符号链接。对于“外部”系统,这些链接似乎已断开,因为它们仅在您进入 chroot 后才指向正确的位置。我还记得一些引导加载程序使用符号链接/boot,只有在初始引导阶段才有意义,当引导分区被挂载为/.

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

  • 我认为 `-type l` 是多余的,因为 `-xtype l` 将在非链接上作为 `-type l` 运行。所以`find -xtype l` 可能就是你所需要的。感谢这种方法。 (13认同)
  • 最后的警告很有用,但请注意,这不适用于 `-L` hack,而是(盲目地)删除一般的损坏符号链接。 (4认同)
  • 请注意,这些解决方案不适用于所有文件系统类型。例如,它不能用于检查 `/proc/XXX/exe` 链接是否损坏。为此,请使用`test -e "$(readlink /proc/XXX/exe)"`。 (3认同)
  • @Flimm`找到。-xtype l` 表示“查找(最终)目标文件是符号链接的所有符号链接”。但是符号链接的最终目标不能是符号链接,否则我们仍然可以跟随链接,它不是最终目标。由于没有这样的符号链接,我们可以将它们定义为其他东西,即损坏的符号链接。 (3认同)
  • @JoóÁdám“它只能是一个符号链接,以防它被破坏”。给“断开的符号链接”或“不存在的文件”一个单独的类型,而不是重载`l`,对我来说不那么令人困惑。 (2认同)

Sam*_*ris 47

symlinks来自http://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gz的命令可用于识别具有各种特征的符号链接。例如:

$ rm a
$ ln -s a b
$ symlinks .
dangling: /tmp/b -> a
Run Code Online (Sandbox Code Playgroud)

  • 显然,`symlinks` 是预装在 Fedora 上的。 (2认同)

小智 39

正如 rozcietrzewiacz 已经评论过的那样,find -L将搜索扩展到符号链接目录可能会产生意想不到的后果,因此不是最佳方法。还没有人提到的是

find /path/to/search -xtype l
Run Code Online (Sandbox Code Playgroud)

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

find /path/to/search -type l -xtype l
Run Code Online (Sandbox Code Playgroud)

迄今为止提出的解决方案都没有检测到循环符号链接,这是另一种类型的破坏。 这个问题涉及可移植性。总而言之,查找损坏的符号链接(包括循环链接)的可移植方法是:

find /path/to/search -type l -exec test ! -e {} \; -print
Run Code Online (Sandbox Code Playgroud)

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

  • 简短、简洁,解决了“find -L”陷阱以及循环链接。+1 (2认同)
  • 好的。最后一个也适用于 MacOSX,而​​@rozcietrzewiacz 的回答没有。 (2认同)
  • @neu242 这可能是因为 *`-xtype`* 没有在 POSIX 中指定,事实上,如果你在 macOS 中查看 *`find(1)`* 它有 *`-type`* 但**不是** *`- xtype`*. (2认同)

kwa*_*ick 9

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

$ find -L . -type l
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

  • 起初我对此表示赞同,但后来我意识到它可能是**危险的**。在您使用它之前,*请[看看我的回答](http://unix.stackexchange.com/a/38691/9382)*! (20认同)

小智 7

如果您需要不同的行为,无论链接是断开的还是循环的,您也可以将 %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
Run Code Online (Sandbox Code Playgroud)

这个例子是从这篇文章中复制的(网站已删除)

参考


小智 7

对于zsh用户:

rm -v -- **/*(-@)
Run Code Online (Sandbox Code Playgroud)

同时删除隐藏的:

rm -v -- **/*(D-@)
Run Code Online (Sandbox Code Playgroud)

来自zsh 用户指南(搜索broken symlinks