在 zsh/Bash 中通配时部分解析/遵循符号链接

phi*_*100 4 bash zsh symlink wildcards

假设我有一个文件a,它是指向 的符号链接b,而它又是指向c.

使用 zsh 的:A修饰符,通配 a 将产生一个绝对路径,解析所有符号链接,因此a(:A)将扩展到c(在具有该realpath库的系统上)的绝对路径。

是否有可能获得b(绝对或相对,但直接作为通配的结果,而不是例如通过查看 的输出ls -l)甚至文件达到任意符号链接深度?

Bash 的解决方案也很有趣。

Sté*_*las 6

您始终可以创建一个与+glob 限定符一起使用的函数:

$ zmodload zsh/stat
$ resolve() { [[ -L $REPLY ]] && stat -A REPLY +link -- ${1-$REPLY}; }
$ print -r - a(+resolve)
乙
$ print -r - a(+resolve:a)
/home/stephane/b (虽然见下面的警告)

请注意,如果这样做a(+resolve+resolve),第二个resolve仍将在原始文件名 ( a)上调用,而不是在第一个resolve( b)的结果上调用。但是,您可以这样做:

$ print -r - a(e['resolve && resolve'])
c
Run Code Online (Sandbox Code Playgroud)

链接两个resolves。但是(警告也适用于:a上面的用法),虽然它适用于这个特定的例子,但在一般情况下这不是一件有效的事情,因为符号链接的目标,当相对路径,是相对于父的符号链接,而不是当前工作目录,因此如果dir/link指向foo,那就是dir/foo文件,而不是foo,因此它仅在解析当前工作目录中的符号链接时有效。

但是,如果我们更改resolve它,它将不再是一个问题,因此它会计算符号链接目标的完整路径:

resolve() {
  local target
  [[ -L $REPLY ]] &&
    stat -A target +link -- ${1-$REPLY} &&
    case $target in
      (/*) REPLY=$target;;
      (*) REPLY=${REPLY:h:a}/$target;;
    esac
}
Run Code Online (Sandbox Code Playgroud)

bash没有 glob 限定符,也没有任何接口readlink()(如zsh's statbuiltin),但在某些系统上,您会找到一个readlink命令:

$ readlink a
b
Run Code Online (Sandbox Code Playgroud)