如何确定相对符号链接是否在某个子树内部?

Fyl*_*lke 7 shell bash symlink

我想测试一个相对符号链接是否指向某个目录的子树。

这个例子会产生,false因为它指向foo目录之外:
/foo>readlink bar
../fie.txt

虽然这个例子会产生true
/foo>readlink bar
fum/fie.txt

是否有我可以利用的现有实用程序,或者我必须从头开始编写代码?我正在使用bash.

Sté*_*las 5

我不认为有这样的实用程序。使用 GNU readlink,您可以执行以下操作:

is_in() (
  needle=$(readlink -ve -- "$1" && echo .) || exit
  haystack=$(readlink -ve -- "$2" && echo .) || exit
  needle=${needle%??} haystack=${haystack%??}
  haystack=${haystack%/} needle=${needle%/}
  case $needle in
    ("$haystack" | "$haystack"/*) true;;
    (*) false;;
  esac
)
Run Code Online (Sandbox Code Playgroud)

这解决了所有符号链接,最终得到了针和干草堆的规范绝对路径。

解释

  • 我们得到了双方的规范化绝对路径干草堆。我们使用-e而不是-f因为我们想确保文件存在。-v如果无法访问文件,该选项会给出错误消息。

  • 与往常一样,--应该用于标记选项和引用的结束,因为我们不想在此处调用 split+glob 运算符。

  • 类似 Bourne 的 shell 中的命令替换有一个缺陷,它会从命令输出的末尾删除所有换行符,而不仅仅是命令添加到最后一行的换行符。这意味着对于像/foo<LF><LF>,$(readlink -ve -- "$1")会返回/foo. 常见的解决方法是附加一个非 LF 字符(此处.)并删除该字符以及由readlinkwith添加的额外 LF 字符var=${var%??}(删除最后两个字符)。

  • 如果针是干草堆或干草堆/某物,则将针视为在干草堆中。但是,如果干草堆是//etc例如不是//something),那将不起作用。/经常需要特别对待,因为虽然//xx斜线数量相同,但一个比另一个高一个级别。

    解决它的一种方法是用/完成的空字符串替换var=${var%/}(唯一以/该结尾的路径readlink -e可能输出是/,因此删除尾随/更改/为空字符串)。

对于文件路径的规范化,您可以使用辅助函数。

canonicalize_path() {
  # canonicalize paths stored in supplied variables. `/` is returned as 
  # the empty string.
  for _var do
    eval '
      '"$_var"'=$(readlink -ve -- "${'"$_var"'}" && echo .) &&
      '"$_var"'=${'"$_var"'%??} &&
      '"$_var"'=${'"$_var"'%/}' || return
  done
}

is_in() (
  needle=$1 haystack=$2
  canonicalize_path needle haystack || exit
  case $needle in
    ("$haystack" | "$haystack"/*) true;;
    (*) false;;
  esac
)
Run Code Online (Sandbox Code Playgroud)