kjo*_*kjo 6 zsh symlink readlink
注意:在这篇文章的原始标题中,我使用了“成熟”的日常意义中的标准一词(因此经过时间考验,与我可以自己动手的快速解决方案形成对比)。然而,在 Unix-talk 的上下文中,“标准”一词具有非常具体(且非常不同)的技术含义。这种对标题中标准一词的另一种更正确的解释使我的帖子的其余部分不一致。(感谢斯特凡Chazelas指出这一点)。因此,我已经修改了标题,更换标准与测试。
作为我在标题中提到的问题的一个例子,假设我有如下所示的目录结构
/tmp/example
??? a/
? ??? b/
? ??? c/
? ??? d/
? ??? target
??? A/
??? B/
??? C/
? ??? D/
? ??? symlink-0 -> ../../symlink-1/b/c/d/target
?
??? symlink-1 -> /tmp/example/a
Run Code Online (Sandbox Code Playgroud)
请注意,这/tmp/example/A/B/C/D/symlink-0是一个符号链接,其直接目标是相对路径:
$ readlink /tmp/example/A/B/C/D/symlink-0
../../symlink-1/b/c/d/target
Run Code Online (Sandbox Code Playgroud)
我想获得与这个直接目标相对应的绝对路径。IOW,我想执行部分分辨率
/tmp/example/A/B/C/D/symlink-0 -> /tmp/example/A/B/symlink-1/b/c/d/target
Run Code Online (Sandbox Code Playgroud)
是否有一个标准的(或者至少是完善的和经过时间考验的)Unix 实用程序来做到这一点?
请注意,完全readlink -f解析路径(到无符号链接的路径);对于这里讨论的案例,例如:
$ readlink -f /tmp/example/A/B/C/D/symlink-0
/tmp/example/a/b/c/d/target
Run Code Online (Sandbox Code Playgroud)
这意味着,readlink -f是不回答我问这里的问题。
我可以通过向以下zsh函数添加足够的错误检查等来推出自己的功能:
canonicalize () {
local abspath=$(dirname $1)/$(readlink $1)
printf -- '%s\n' $abspath:a
}
Run Code Online (Sandbox Code Playgroud)
...但我已经学会(艰难的方式)不要低估稳健实施此类实用程序的难度,因此如果可能,我更愿意使用现有工具。
FWIW,下面的脚本生成了这篇文章的例子:
mkdir -p /tmp/example/a/b/c/d /tmp/example/A/B/C/D
touch /tmp/example/a/b/c/d/target
ln -s /tmp/example/a /tmp/example/A/B/symlink-1
ln -s ../../symlink-1/b/c/d/target /tmp/example/A/B/C/D/symlink-0
Run Code Online (Sandbox Code Playgroud)
我不知道有任何这样的实用程序。然而,你的方法是有缺陷的(我同意很难做到正确)。
该:a修饰符计算绝对路径,无需访问文件系统。特别是,无论是否是符号链接,它都会更改a/b/..为。aa/b
如果您有/a/b -> ../foo符号链接,则/foo仅当/a它本身不是符号链接时才有效。即使您规范化$(dirname $1),它仍然不适用于符号链接,就像/a/b -> x/../../foo它x本身是符号链接一样。
在你的情况下:
/tmp/example/A/B/C/D/symlink-0 -> ../../symlink-1/b/c/d/target
Run Code Online (Sandbox Code Playgroud)
解析为/tmp/example/A/B/symlink-1/b/c/d/target只是因为符号链接/tmp/example/A/B/C/D也不/tmp/example/A/B/C是。
换句话说,要获得不含..组件的符号链接目标的绝对路径,您可能必须解析多个符号链接,并且无法通过组合文件路径和符号链接目标来单独完成此操作。
如果您想要这样的路径,最简单的(我想说只有合理和/或有用的)方法是获取符号链接目标的规范路径,即所有路径组件既不是..,.也不是符号链接,除非可能最后。为此,你可以这样做:
zmodload -F zsh/stat b:zstat
canonicalize1() {
if [ -L "$1" ]; then
local link
zstat -A link +link -- "$1" || return
case $link in
(/*) ;;
(*)
case $1:h in
(*/) link=$1:h$link;;
(*) link=$1:h/$link;;
esac;;
esac
printf '%s\n' $link:h:A/$link:t
else
printf '%s\n' $1:A
fi
}
Run Code Online (Sandbox Code Playgroud)
在您的/tmp/example/A/B/C/D/symlink-0符号链接上,仍然给出/tmp/example/a/b/c/d/target,因为符号链接的目标不是符号链接,但如果这不是您想要的,那么我会问:执行以下操作时您想要什么结果:
canonicalize1 /tmp/x/y
Run Code Online (Sandbox Code Playgroud)
/tmp/x/y到 的符号链接在哪里../foo以及/tmp/x到 的符号链接/a/b/c和/a, /a/b,/a/b/c本身也是符号链接吗?