给定一个绝对路径或相对路径(在类unix系统中),我希望在解析任何中间符号链接之后确定目标的完整路径。同时还可以解析~用户名符号。

如果目标是一个目录,则可以将chdir()放入该目录,然后调用getcwd(),但我确实希望从shell脚本而不是编写C helper来完成此操作。不幸的是,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"。


当前回答

我的答案在这里Bash:如何获得一个符号链接的真正路径?

但简而言之,在脚本中非常方便:

script_home=$( dirname $(realpath "$0") )
echo Original script home: $script_home

这些是GNU coreutils的一部分,适合在Linux系统中使用。

为了测试一切,我们把symlink放到/home/test2/,修改一些额外的东西,并从根目录运行/调用它:

/$ /home/test2/symlink
/home/test
Original script home: /home/test

在哪里

Original script is: /home/test/realscript.sh
Called script is: /home/test2/symlink

其他回答

把一些给定的解决方案放在一起,知道readlink在大多数系统上可用,但需要不同的参数,这对我来说在OSX和Debian上工作得很好。我对BSD系统不太确定。也许条件需要为[[$OSTYPE != darwin*]],以仅从OSX中排除-f。

#!/bin/bash
MY_DIR=$( cd $(dirname $(readlink `[[ $OSTYPE == linux* ]] && echo "-f"` $0)) ; pwd -P)
echo "$MY_DIR"

下面是如何使用内联Perl脚本在MacOS/Unix中获得文件的实际路径:

FILE=$(perl -e "use Cwd qw(abs_path); print abs_path('$0')")

类似地,要获取符号链接文件的目录:

DIR=$(perl -e "use Cwd qw(abs_path); use File::Basename; print dirname(abs_path('$0'))")

我的答案在这里Bash:如何获得一个符号链接的真正路径?

但简而言之,在脚本中非常方便:

script_home=$( dirname $(realpath "$0") )
echo Original script home: $script_home

这些是GNU coreutils的一部分,适合在Linux系统中使用。

为了测试一切,我们把symlink放到/home/test2/,修改一些额外的东西,并从根目录运行/调用它:

/$ /home/test2/symlink
/home/test
Original script home: /home/test

在哪里

Original script is: /home/test/realscript.sh
Called script is: /home/test2/symlink
readlink -f "$path"

编者注:上述内容适用于GNU readlink和FreeBSD/PC-BSD/OpenBSD readlink,但不适用于10.11版本的OS X。 GNU readlink提供了额外的相关选项,例如-m用于解析符号链接,无论最终目标是否存在。

注意,自从GNU coreutils 8.15(2012-01-06)以来,有一个realpath程序可用,它不那么迟钝,而且比上面的程序更灵活。它还兼容同名的FreeBSD util。它还包括在两个文件之间生成相对路径的功能。

realpath $path

[管理员添加以下评论由halloleo -danorton]

对于Mac OS X(至少10.11.x),使用不带-f选项的readlink:

readlink $path

编者注:这将不会递归地解析符号链接,因此不会报告最终目标;例如,给定指向b的符号链接a, b又指向c,这将只报告b(并且不会确保它作为绝对路径输出)。 在OS X上使用以下perl命令来填补缺少readlink -f功能的空白: perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"

普通shell脚本通常必须找到它们的“主”目录,即使它们是作为符号链接调用的。因此脚本必须从$0开始找到它们的“真实”位置。

cat `mvn`

在我的系统上输出一个包含以下内容的脚本,这应该能很好地提示您需要什么。

if [ -z "$M2_HOME" ] ; then
  ## resolve links - $0 may be a link to maven's home
  PRG="$0"

  # 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`