如何在Shell脚本中解析符号链接
给定绝对路径或者相对路径(在类Unix系统中),我想在解决所有中间符号链接后确定目标的完整路径。同时解决〜username表示法的奖励点。
如果目标是目录,则可以将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目录中执行时,resolve(" foo")==" / Users / greg / tmp / bar"。
解决方案
回答
根据标准,pwd -P
应该返回符号链接已解析的路径。
来自unistd.h的C函数char * getcwd(char * buf,size_t size)应该具有相同的行为。
getcwd
密码
回答
即使将它们作为符号链接调用,常见的Shell脚本也常常必须找到其"主"目录。因此,脚本必须仅从$ 0中找到其"真实"位置。
cat `mvn`
在我的系统上会打印一个包含以下内容的脚本,这应该是我们所需要的一个很好的提示。
if [ -z "$M2_HOME" ] ; then ## resolve links -readlink -f "$path"may be a link to maven's home PRG="realpath $path" # need this for relative symlinks while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG="`dirname "$PRG"`/$link" fi done saveddir=`pwd` M2_HOME=`dirname "$PRG"`/.. # make it fully qualified M2_HOME=`cd "$M2_HOME" && pwd`
回答
readlink $path
编者注:上面的代码适用于GNUreadlink
和FreeBSD / PC-BSD / OpenBSDreadlink
,但不适用于OS X 10.11及更高版本。
GNUreadlink
提供了其他相关选项,例如-m来解析符号链接,无论最终目标是否存在。
请注意,自GNU coreutils 8.15(2012-01-06)起,提供了一个Realpath程序,该程序比上面的程序更钝和更灵活。它也与同名的FreeBSD util兼容。它还包括在两个文件之间生成相对路径的功能。
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.
[以下管理员补充来自halloleo danorton的评论]
对于Mac OS X(至少通过10.11.x版本),请使用不带-f选项的readlink
:
#!/bin/bash # get the absolute path of the executable SELF_PATH=$(cd -P -- "$(dirname -- "##代码##")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "##代码##") # 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
编者注:这不会递归解析符号链接,因此不会报告最终目标。例如,给定符号链接" a"指向" b",而符号链接又指向" c",则仅报告" b"(并且不会确保将其输出为绝对路径)。
在OS X上使用以下perl
命令来填补缺少的readlink -f
功能的空白:
perl -MCwd -le'打印Cwd :: abs_path(shift)'" $ path"`
回答
我的最爱之一是" realpath foo"
##代码##回答
如果只需要目录," pwd -P"似乎可以工作,但是如果出于某些原因想要实际可执行文件的名称,我认为这无济于事。这是我的解决方案:
##代码##