Philippe Asked: 2019-12-22 02:46:32 +0800 CST2019-12-22 02:46:32 +0800 CST 2019-12-22 02:46:32 +0800 CST 在 bash 中是否有一个内置命令来获取相对文件路径的绝对路径? 772 我可以使用外部命令realpath来获取文件的绝对路径: realpath tmp/toto 返回 /home/john/tmp/toto 我可以使用bash内置来获得相同的效果吗? bash shell 4 个回答 Voted Kusalananda 2019-12-22T03:35:49+08:002019-12-22T03:35:49+08:00 bashshell 没有内置方法来显式获取给定相对路径名的绝对路径。 在zsh外壳中,可以做 pathname=../../home/kk/.zshenv print -r -- $pathname:P 并/home/kk/.zshenv返回(请注意,它还尽可能以类似的方式解析所有符号链接realpath())。 在bash中,对于指定非目录的路径名并假设您具有对其父目录的搜索访问权限,您可以使用 $ pathname=../../home/kk/.zshenv $ ( OLDPWD=- CDPATH= cd -P -- "${pathname%/*}" && printf '%s/%s\n' "$PWD" "${pathname##*/}" ) /home/kk/.zshenv 也就是说,暂时(在子shell中)cd保存文件的目录,然后使用路径名的值$PWD和文件名组件构造绝对路径名。-P需要避免对组件进行cd特殊处理。..它具有解析目录本身中的符号链接组件的副作用。但是,如果文件本身是符号链接,则不会被解析(这与zsh':P修饰符不同)。 我们着手OLDPWD解决执行 a而不是-的事实(该技巧适用于但并非所有其他实现)。cd -P -- -chdir($OLDPWD)chdir("-")bashsh 对于目录路径,它更容易: $ pathname=../../home/kk $ ( OLDPWD=- CDPATH= cd -P -- "$pathname" && pwd ) /home/kk 为了方便起见,这显然可以放入 shell 函数中: myrealpath () ( if [[ -d $1 ]]; then OLDPWD=- CDPATH= cd -P -- "$1" && pwd else OLDPWD=- CDPATH= cd -P -- "${1%/*}" && printf '%s/%s\n' "$PWD" "${1##*/}" fi ) (请注意,整个函数是在子 shell 中定义的,以避免更改调用 shell 的工作目录。) 测试这个功能: $ myrealpath ../../home/kk /home/kk $ myrealpath ../../home/kk/.zshenv /home/kk/.zshenv 根据操作系统,使用不带参数的函数将返回当前目录的绝对路径或给出错误。在 的未来版本中bash,这可能是每个系统上的错误,因为cd ''失败将成为 POSIX 要求。 Best Answer mr.spuratic 2019-12-24T05:00:25+08:002019-12-24T05:00:25+08:00 Bash 带有一个realpath可加载的扩展。由于 bash-4.4 这应该默认安装¹,所以你应该能够做到: BASH_LOADABLES_PATH=${BASH_LOADABLES_PATH:-/usr/local/lib/bash:/usr/lib/bash} enable -f realpath realpath realpath .. help realpath 一旦启用,每个可加载命令都成为一个“真正的”内置命令,没有额外的 fork/exec 开销,并且能够操纵 bash 环境(如果提供,例如mypid可加载).. 该-f选项指定可加载扩展二进制文件的路径,如果它不在预期的位置或您的发行版没有正确设置它,您需要将变量设置为BASH_LOADABLES_PATH包含扩展的目录(或者,使用-f完整路径到可加载)。如果设置正确,则不需要上面的第一行。 在编写更喜欢但不需要此类扩展的可移植脚本时,无论如何我都会使用包装函数——沿着@Kusalananda 的思路——以便它可以回退到外部(例如readlink或realpath来自coreutils)。 这个扩展从 bash-2.05 开始可用,但在 bash-4.4 之前,默认情况下没有编译和安装扩展,但如果你有一个工作的构建环境(C 编译器等),这样做很简单。发行版可能包含也可能不包含扩展,遗憾的是 RHEL 8(以及因此的 CentOS 8)构建 bash-4.4 并故意删除了可加载的扩展。 jrw32982 2019-12-27T22:01:32+08:002019-12-27T22:01:32+08:00 我建议以下,它们很有可能在非 Linux 操作系统(包括 AIX)上工作。要计算绝对路径(即从 开始的路径/): abspath() { [[ $1 = /* ]] && printf "%s\n" "$1" || printf "%s\n" "$PWD/$1" } 对于规范路径(即扩展所有符号链接的路径): canonical_path() { perl -mCwd -le ' print Cwd::abs_path $ARGV[0] ' -- "$1" } 在针对其他可能的解决方案(包括对 的调用realpath)进行测试时,您会注意到一个显着差异,具体取决于最后一个路径组件是否存在,以及最后一个路径组件是否是符号链接。 Alex N. 2019-12-22T03:07:32+08:002019-12-22T03:07:32+08:00 一些系统拥有“realpath”命令,例如 Ubuntu。你可以试试realpath ~/foo.txt,它可以给出类似的东西/home/user/foo.txt,然后你可以用它basedir来切断文件名。
bash
shell 没有内置方法来显式获取给定相对路径名的绝对路径。在
zsh
外壳中,可以做并
/home/kk/.zshenv
返回(请注意,它还尽可能以类似的方式解析所有符号链接realpath()
)。在
bash
中,对于指定非目录的路径名并假设您具有对其父目录的搜索访问权限,您可以使用也就是说,暂时(在子shell中)
cd
保存文件的目录,然后使用路径名的值$PWD
和文件名组件构造绝对路径名。-P
需要避免对组件进行cd
特殊处理。..
它具有解析目录本身中的符号链接组件的副作用。但是,如果文件本身是符号链接,则不会被解析(这与zsh
':P
修饰符不同)。我们着手
OLDPWD
解决执行 a而不是-
的事实(该技巧适用于但并非所有其他实现)。cd -P -- -
chdir($OLDPWD)
chdir("-")
bash
sh
对于目录路径,它更容易:
为了方便起见,这显然可以放入 shell 函数中:
(请注意,整个函数是在子 shell 中定义的,以避免更改调用 shell 的工作目录。)
测试这个功能:
根据操作系统,使用不带参数的函数将返回当前目录的绝对路径或给出错误。在 的未来版本中
bash
,这可能是每个系统上的错误,因为cd ''
失败将成为 POSIX 要求。Bash 带有一个
realpath
可加载的扩展。由于 bash-4.4 这应该默认安装¹,所以你应该能够做到:一旦启用,每个可加载命令都成为一个“真正的”内置命令,没有额外的 fork/exec 开销,并且能够操纵 bash 环境(如果提供,例如
mypid
可加载)..该
-f
选项指定可加载扩展二进制文件的路径,如果它不在预期的位置或您的发行版没有正确设置它,您需要将变量设置为BASH_LOADABLES_PATH
包含扩展的目录(或者,使用-f
完整路径到可加载)。如果设置正确,则不需要上面的第一行。在编写更喜欢但不需要此类扩展的可移植脚本时,无论如何我都会使用包装函数——沿着@Kusalananda 的思路——以便它可以回退到外部(例如
readlink
或realpath
来自coreutils)。我建议以下,它们很有可能在非 Linux 操作系统(包括 AIX)上工作。要计算绝对路径(即从 开始的路径
/
):对于规范路径(即扩展所有符号链接的路径):
在针对其他可能的解决方案(包括对 的调用
realpath
)进行测试时,您会注意到一个显着差异,具体取决于最后一个路径组件是否存在,以及最后一个路径组件是否是符号链接。一些系统拥有“realpath”命令,例如 Ubuntu。你可以试试
realpath ~/foo.txt
,它可以给出类似的东西/home/user/foo.txt
,然后你可以用它basedir
来切断文件名。