如何获得完整的路径,*允许*符号链接

How to obtain the full PATH, *allowing* for symbolic links

我编写了 bash 接受目录名作为参数的脚本。单个点 ('.') 是有效的目录名称,但有时我需要知道“.”在哪里是。 readlinkrealpath 命令提供了一个解析路径,这没有帮助,因为我需要允许符号 links.

例如,给定目录的解析路径可能类似于 /mnt/vol_01/and/then/some,而脚本是用“.”调用的。在哪里 '。'是 /app/then/some(一个符号 link,它将解析为我给出的第一条路径)。

为了解决我的问题,我所做的是结合使用 cdpwd 来提供我想要的完整路径,目前看来一切正常。

脚本的简化示例:

DEST_DIR=

# Convert the given destination directory to a full path, ALLOWING 
# for symbolic links.  This is necessary in cases where '.' is 
# given as the destination directory.
DEST_DIR=$(cd $DEST_DIR && pwd -L)

# Do stuff in $DEST_DIR

我的问题是:我使用 cdpwd 是获得我想要的东西的最佳方式吗?或者有更好的方法吗?

如果您想做的只是创建一个与相对路径相比变化最小的绝对路径,那么一个简单、安全、快速的方法是:

[[ $dest_dir == /* ]] || dest_dir=$PWD/$dest_dir

(请参阅 Correct Bash and shell script variable capitalization 以了解为什么 dest_dir 优于 DEST_DIR。)

即使该目录(尚)不存在,或者如果无法 cd 访问它(例如,因为它的权限不允许),上面的代码也可以工作。它可能会产生带有冗余“.”的路径。组件、“..”组件和冗余斜杠(“/a//b”、“//a/b/”、...)。

如果您想要一个最少清理的路径(留下未解析的符号链接),那么原始代码的修改版本可能是一个合理的选择:

dest_dir=$(cd -- "$dest_dir"/ && pwd)
  • -- 是处理以“-”开头的目录名称所必需的。
  • "$dest_dir" 中的引号是处理包含空格(实际上是 $IFS 个字符)或 glob 字符的名称所必需的。
  • "$dest_dir"/ 上的尾部斜线是处理相对名称仅为 -.
  • 的目录所必需的
  • 普通 pwd 就足够了,因为它的行为就像默认指定 -L 一样。

请注意,如果 cd 失败,代码会将 dest_dir 设置为空字符串。你可能想在对变量做任何其他事情之前检查一下。

另请注意,$(cd ...) 将创建一个带有 Bash 的子 shell。这在某种程度上很好,因为之后不需要 cd 回到起始目录(这可能是不可能的),但如果你经常这样做(例如在循环中),它可能会导致性能问题。

最后,请注意,如果目录名称包含一个或多个尾随换行符(例如,由 mkdir $'dir\n' 创建),代码将不起作用。有可能解决这个问题(如果你真的关心它的话),但它很麻烦。参见 How to avoid bash command substitution to remove the newline character? and shell: keep trailing newlines ('\n') in command substitution。一种可能的方法是:

dest_dir=$(cd -- "$dest_dir"/ && printf '%s.' "$PWD")    # Add a trailing '.'
dest_dir=${dest_dir%.}                                   # Remove the trailing '.'