给定绝对或相对路径(在类Unix系统中),我想在解析任何中间符号链接后确定目标的完整路径.奖励积分也可以同时解析〜用户名表示法.
如果目标是目录,则可以将chdir()放入目录然后调用getcwd(),但我真的想从shell脚本而不是编写C帮助程序.不幸的是,shell倾向于试图隐藏用户的符号链接(这是OS X上的bash):
$ ls -ld foo bar drwxr-xr-x 2 greg greg 68 Aug 11 22:36 bar lrwxr-xr-x 1 greg greg 3 Aug 11 22:36 foo -> bar $ cd foo $ pwd /Users/greg/tmp/foo $
我想要的是一个函数resolve(),这样当从上例中的tmp目录执行时,解析("foo")=="/ Users/greg/tmp/bar".
readlink -f "$path"
编者注:以上内容适用于GNU readlink
和FreeBSD/PC-BSD/OpenBSD readlink
,但从10.11开始不适用于OS X.
GNU readlink
提供了其他相关选项,例如,-m
无论最终目标是否存在,都可以解析符号链接.
请注意,自GNU coreutils 8.15(2012-01-06)以来,有一个可用的实际路径程序比上面的更简单,更灵活.它还与同名的FreeBSD util兼容.它还包括生成两个文件之间的相对路径的功能.
realpath $path
[管理员在下面评论halloleo - danorton]
对于Mac OS X(通过至少10.11.x),请使用readlink
不带-f
选项:
readlink $path
编者注:这不会递归地解析符号链接,因此不会报告最终目标; 例如,给定a
指向的符号链接指向(仅b
指向)c
,这只会报告b
(并且不会确保它作为绝对路径输出).在OS X上
使用以下perl
命令填补缺少的readlink -f
功能的空白:
perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"
根据标准,pwd -P
应该返回解决了符号链接的路径.
C函数char *getcwd(char *buf, size_t size)
从unistd.h
应具有相同的行为.
getcwd pwd
如果您只是想要目录,"pwd -P"似乎有效,但如果由于某种原因您想要实际可执行文件的名称,我认为这没有帮助.这是我的解决方案:
#!/bin/bash # get the absolute path of the executable SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") # resolve symlinks while [[ -h $SELF_PATH ]]; do # 1) cd to directory of the symlink # 2) cd to the directory of where the symlink points # 3) get the pwd # 4) append the basename DIR=$(dirname -- "$SELF_PATH") SYM=$(readlink "$SELF_PATH") SELF_PATH=$(cd "$DIR" && cd "$(dirname -- "$SYM")" && pwd)/$(basename -- "$SYM") done
我最喜欢的一个是 realpath foo
realpath - return the canonicalized absolute pathname realpath expands all symbolic links and resolves references to '/./', '/../' and extra '/' characters in the null terminated string named by path and stores the canonicalized absolute pathname in the buffer of size PATH_MAX named by resolved_path. The resulting path will have no symbolic link, '/./' or '/../' components.
readlink -e [filepath]
似乎正是你所要求的 - 它接受一个arbirary路径,解析所有符号链接,并返回"真实"路径 - 它可能是所有系统已经拥有的"标准*nix"
其他方式:
# Gets the real path of a link, following all links myreadlink() { [ ! -h "$1" ] && echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : '.*-> \(.*\)$')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\([^/].*\)\$|$(dirname $1)/\1|"); } # Returns the absolute path to a command, maybe in $PATH (which) or not. If not found, returns the same whereis() { echo $1 | sed "s|^\([^/].*/.*\)|$(pwd)/\1|;s|^\([^/]*\)$|$(which -- $1)|;s|^$|$1|"; } # Returns the realpath of a called command. whereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\([^/].*\)\$|$(dirname ${SCRIPT_PATH})/\1|"; }
将一些给定的解决方案放在一起,知道readlink在大多数系统上都可用,但需要不同的参数,这对我在OSX和Debian上运行良好.我不确定BSD系统.也许条件需要仅从OSX中[[ $OSTYPE != darwin* ]]
排除-f
.
#!/bin/bash MY_DIR=$( cd $(dirname $(readlink `[[ $OSTYPE == linux* ]] && echo "-f"` $0)) ; pwd -P) echo "$MY_DIR"