如何获得完整的路径,*允许*符号链接
How to obtain the full PATH, *allowing* for symbolic links
我编写了 bash 接受目录名作为参数的脚本。单个点 ('.') 是有效的目录名称,但有时我需要知道“.”在哪里是。 readlink
和 realpath
命令提供了一个解析路径,这没有帮助,因为我需要允许符号 links.
例如,给定目录的解析路径可能类似于 /mnt/vol_01/and/then/some
,而脚本是用“.”调用的。在哪里 '。'是 /app/then/some
(一个符号 link,它将解析为我给出的第一条路径)。
为了解决我的问题,我所做的是结合使用 cd
和 pwd
来提供我想要的完整路径,目前看来一切正常。
脚本的简化示例:
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
我的问题是:我使用 cd
和 pwd
是获得我想要的东西的最佳方式吗?或者有更好的方法吗?
如果您想做的只是创建一个与相对路径相比变化最小的绝对路径,那么一个简单、安全、快速的方法是:
[[ $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 '.'
我编写了 bash 接受目录名作为参数的脚本。单个点 ('.') 是有效的目录名称,但有时我需要知道“.”在哪里是。 readlink
和 realpath
命令提供了一个解析路径,这没有帮助,因为我需要允许符号 links.
例如,给定目录的解析路径可能类似于 /mnt/vol_01/and/then/some
,而脚本是用“.”调用的。在哪里 '。'是 /app/then/some
(一个符号 link,它将解析为我给出的第一条路径)。
为了解决我的问题,我所做的是结合使用 cd
和 pwd
来提供我想要的完整路径,目前看来一切正常。
脚本的简化示例:
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
我的问题是:我使用 cd
和 pwd
是获得我想要的东西的最佳方式吗?或者有更好的方法吗?
如果您想做的只是创建一个与相对路径相比变化最小的绝对路径,那么一个简单、安全、快速的方法是:
[[ $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 '.'