跟踪整个链接链

跟踪整个链接链

我周围散落着大量像这样的链式符号链接:

A(符号链接)-> B(符号链接)-> C(文件)

有些甚至可能涉及更长的链,但我还不确定。

当手动检查单个文件时,很容易看到发生了什么,但我正在寻找一种自动化的方法来找到这些文件并(最好)清理它们。

在上面的例子中,我希望 B->C 符号链接保持不变,但 A->B 符号链接将变为 A->C

识别它们是主要目标;数量可能最终足够少,因此手动修复它们并不是什么大问题。但手动找到它们并不可行。

我知道“符号链接”实用程序,它在许多情况下都很有用,例如查找悬空的符号链接,但它似乎没有能力检测这样的“链”

我知道“find -type l”以及 find 的 -L 选项,但它们似乎不能一起工作,因为“find -L -type l”总是返回空响应。

我使用“find -type l -exec ls -l {} +”(效果比 find 的 -ls 选项更好)并尝试使用它来获取符号链接目标列表,然后我可以检查它们是否是符号链接,但是,所有符号链接都是相对的而不是绝对的,因此输出有点混乱

例如我得到如下输出:

lrwxrwxrwx 1 username 50 Nov  5 01:00  ./a/b/c/d -> ../../e/f/g/h

从那以后,我不得不想一想,才能弄清楚实际的符号链接目标是 ./a/e/f/g/h(然后我可以检查它是否是符号链接),这对于自动化来说并不理想

如果符号链接(暂时)是绝对的而不是相对的,这会更容易,但“符号链接”实用程序只能将绝对转换为相对;据我所知,它不能将相对转换为绝对。

答案1

跟踪整个链接链

真实路径

真实路径(1)为您提供链接的绝对目的地。但它只为您提供最终的目的地,所以如果您有一个链接链,它只会显示该链最终指向的最后一个真实文件/文件夹的路径。

因此,对于您的情况,如果../../e/f/g/h是真实文件或文件夹,您将看到绝对路径。但如果其中一个组件也是符号链接,它将继续递归,直到解析途中的所有符号链接。

阅读链接

您还可以使用readlink(1)带有 -f 或 -e 标志的命令,这将为您提供类似的结果realpath

  -f, --canonicalize            canonicalize by following every symlink in
                                every component of the given name recursively;
                                all but the last component must exist
  -e, --canonicalize-existing   canonicalize by following every symlink in
                                every component of the given name recursively,
                                all components must exist

避免遵循整个链接链

如果我理解正确的话,您不想跟踪到最后一个组件,而只想获取实际链接的绝对路径。这有点丑陋,但您可以执行以下操作:

LINK=./a/b/c/d
/usr/bin/realpath --no-symlinks "$(dirname ${LINK})/$(readlink ${LINK})"

解释:

$ dirname $LINK # dirname ./a/b/c/d
./a/b/c

$ readlink $LINK # readlink ./a/b/c/d
../../e/f/g/h

$ echo "$(dirname ${LINK})/$(readlink ${LINK})" 
./a/b/c/../../e/f/g/h

$ /usr/bin/realpath --no-symlinks "$(dirname ${LINK})/$(readlink ${LINK})"
/home/a/e/f/g/h

如果您只想查看相对于 CWD 的链接,您可以添加 --relative-to 参数:

$ /usr/bin/realpath --no-symlinks --relative-to ./ "$(dirname ${LINK})/$(readlink ${LINK})"
a/e/f/g/h

使用 find

您可以使用 find 命令获取我之前展示的 realpath 命令的参数:

$ find ./ -type l -printf "%h/%l\n"
./a/b/c/../../e/f/g/h

从 man 中查找:

%h     Leading directories of file's name (all but the last element).   If
       the  file  name  contains  no  slashes  (since it is in the current
       directory) the %h specifier expands to ".".

%l     Object of symbolic link (empty string if file is not a symbolic link).

然后您可以将它与上面的 realpath 命令结合起来。

$ find ./ -type l -printf "%h/%l\n" | xargs /usr/bin/realpath -s
/home/a/e/f/g/h

如果您只想查看与您的 CWD 相关的链接:

$ find ./ -type l -printf "%h/%l\n" | xargs /usr/bin/realpath -s --relative-to ./
a/e/f/g/h

相关内容