在Linux上,readlink实用程序接受附加链接后面的选项-f。这似乎不适用于Mac和基于BSD的系统。等价的是什么?
下面是一些调试信息:
$ which readlink; readlink -f
/usr/bin/readlink
readlink: illegal option -f
usage: readlink [-n] [file ...]
在Linux上,readlink实用程序接受附加链接后面的选项-f。这似乎不适用于Mac和基于BSD的系统。等价的是什么?
下面是一些调试信息:
$ which readlink; readlink -f
/usr/bin/readlink
readlink: illegal option -f
usage: readlink [-n] [file ...]
当前回答
真正的平台独立也是r -online
readlink(){ RScript -e "cat(normalizePath(commandArgs(T)[1]))" "$1";}
要实际模拟readlink -f <path>,需要使用$2而不是$1。
其他回答
FreeBSD和OSX都有一个来自NetBSD的statage版本。
您可以使用格式开关调整输出(参见上面链接的手册页)。
% cd /service
% ls -tal
drwxr-xr-x 22 root wheel 27 Aug 25 10:41 ..
drwx------ 3 root wheel 8 Jun 30 13:59 .s6-svscan
drwxr-xr-x 3 root wheel 5 Jun 30 13:34 .
lrwxr-xr-x 1 root wheel 30 Dec 13 2013 clockspeed-adjust -> /var/service/clockspeed-adjust
lrwxr-xr-x 1 root wheel 29 Dec 13 2013 clockspeed-speed -> /var/service/clockspeed-speed
% stat -f%R clockspeed-adjust
/var/service/clockspeed-adjust
% stat -f%Y clockspeed-adjust
/var/service/clockspeed-adjust
某些OS X版本的stat可能没有-f%R选项用于格式化。在这种情况下-stat -f%Y就足够了。-f%Y选项将显示符号链接的目标,而-f%R显示与文件对应的绝对路径名。
编辑:
如果你能使用Perl (Darwin/OS X安装了最新版本的Perl),那么:
perl -MCwd=abs_path -le 'print abs_path readlink(shift);' linkedfile.txt
将工作。
MacPorts和Homebrew提供了包含greadlink (GNU readlink)的coreutils包。这要归功于Michael Kallweitt在mackb.com上的帖子。
brew install coreutils
greadlink -f file.txt
Perl有一个readlink函数(例如,如何在Perl中复制符号链接?)这适用于大多数平台,包括OS X:
perl -e "print readlink '/path/to/link'"
例如:
$ mkdir -p a/b/c
$ ln -s a/b/c x
$ perl -e "print readlink 'x'"
a/b/c
一个简单的perl单行程序,几乎可以在任何地方工作,没有任何外部依赖:
perl -MCwd -e 'print Cwd::abs_path shift' ~/non-absolute/file
将解除对符号链接的引用。
脚本中的用法可能是这样的:
readlinkf(){ perl -MCwd -e 'print Cwd::abs_path shift' "$1";}
ABSPATH="$(readlinkf ./non-absolute/file)"
您可能既需要可移植的纯shell实现,也需要单元测试覆盖率,因为此类情况的边缘情况的数量非常多。
查看我的项目在Github上的测试和完整代码。下面是实现的概要:
正如Keith Smith敏锐地指出的那样,readlink -f做了两件事:1)递归地解析符号链接,2)规范化结果,因此:
realpath() {
canonicalize_path "$(resolve_symlinks "$1")"
}
首先,符号链接解析器实现:
resolve_symlinks() {
local dir_context path
path=$(readlink -- "$1")
if [ $? -eq 0 ]; then
dir_context=$(dirname -- "$1")
resolve_symlinks "$(_prepend_path_if_relative "$dir_context" "$path")"
else
printf '%s\n' "$1"
fi
}
_prepend_path_if_relative() {
case "$2" in
/* ) printf '%s\n' "$2" ;;
* ) printf '%s\n' "$1/$2" ;;
esac
}
请注意,这是完整实现的略微简化版本。完整的实现为符号链接循环添加了一个小检查,并对输出进行了一些处理。
最后,规范化路径的函数:
canonicalize_path() {
if [ -d "$1" ]; then
_canonicalize_dir_path "$1"
else
_canonicalize_file_path "$1"
fi
}
_canonicalize_dir_path() {
(cd "$1" 2>/dev/null && pwd -P)
}
_canonicalize_file_path() {
local dir file
dir=$(dirname -- "$1")
file=$(basename -- "$1")
(cd "$dir" 2>/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file")
}
差不多就是这样。简单到可以粘贴到您的脚本中,但也非常棘手,如果您依赖于任何用例中没有单元测试的代码,那就太疯狂了。