给定一个绝对路径或相对路径(在类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

其他回答

根据标准,pwd -P应该返回已解析符号链接的路径。

C函数char *getcwd(char *buf, size_t size)从unistd.h应该有相同的行为。

getcwd 松材线虫病

试试这个:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))

下面是如何使用内联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中的符号链接解析器,无论链接是目录还是非目录都可以工作:

function readlinks {(
  set -o errexit -o nounset
  declare n=0 limit=1024 link="$1"

  # If it's a directory, just skip all this.
  if cd "$link" 2>/dev/null
  then
    pwd -P
    return 0
  fi

  # Resolve until we are out of links (or recurse too deep).
  while [[ -L $link ]] && [[ $n -lt $limit ]]
  do
    cd "$(dirname -- "$link")"
    n=$((n + 1))
    link="$(readlink -- "${link##*/}")"
  done
  cd "$(dirname -- "$link")"

  if [[ $n -ge $limit ]]
  then
    echo "Recursion limit ($limit) exceeded." >&2
    return 2
  fi

  printf '%s/%s\n' "$(pwd -P)" "${link##*/}"
)}

注意,所有的cd和set都发生在一个子shell中。

为了解决Mac不兼容的问题,我想到了

echo `php -r "echo realpath('foo');"`

不是很好,但是跨越了操作系统