将相对路径转换为绝对路径,无需符号链接

将相对路径转换为绝对路径,无需符号链接

是否有一个 Unix 命令可以从可能包含符号链接的相对路径获取绝对(和规范化)路径?

答案1

您可以使用readlink实用程序,带有-f选项:

-f, --canonicalize

      canonicalize  by  following  every symlink in every component of
      the given name recursively; all  but  the  last  component  must
      exist

某些发行版,例如使用GNU 核心工具自由BSD,还附带一个realpath(1)基本上只调用的实用程序realpath(3)并且做几乎同样的事情。

答案2

便携式地,PWD多变的由 shell 设置为当前目录的一个绝对位置。该路径的任何组件都可以是符号链接。

case $f in
  /*) absolute=$f;;
  *) absolute=$PWD/$f;;
esac

如果您想删除...,请切换到包含该文件的目录并$PWD在那里获取:

if [ -d "$f" ]; then f=$f/.; fi
absolute=$(cd "$(dirname -- "$f")"; printf %s. "$PWD")
absolute=${absolute%?}
absolute=$absolute/${f##*/}

没有可移植的方法来跟踪符号链接。如果您有一个目录路径,那么大多数 unice$(cd -- "$dir" && pwd -P 2>/dev/null || pwd)都会提供不使用符号链接的路径,因为跟踪符号链接的 shell 往往会实现pwd -P(“P”代表“物理”)。

一些 unice 提供了一个实用程序来打印文件的“物理”路径。

  • 最近的 Linux 系统(带有 GNU coreutils 或 BusyBox)具有readlink -f,FreeBSD ≥8.3、NetBSD ≥4.0 以及 OpenBSD 早至 2.2 也是如此。
  • FreeBSD ≥4.3 有realpath(它也存在于某些 Linux 系统上,并且位于 BusyBox 中)。
  • 如果 Perl 可用,您可以使用Cwd模块

    perl -MCwd -e 'print Cwd::realpath($ARGV[0])' path/to/file
    

答案3

pwd适合您的需求吗?它给出当前目录的绝对路径。或者也许你想要的是真实路径()

答案4

这里的其他答案都很好,但不足以满足我的需求。我需要一个可以在任何计算机上的脚本中使用的解决方案。我的解决方案是编写一个 shell 脚本,我可以从需要的脚本中调用它。

#!/bin/sh
if [ $# -eq 0 ] || [ $# -gt 2 ]; then
  printf 'Usage: respath path [working-directory]\n' >&2
  exit 1
fi
cantGoUp=

path=$1
if [ $# -gt 1 ]; then
  cd "$2"
fi
cwd=`pwd -P` #Use -P option to account for directories that are actually symlinks

#Handle non-relative paths, which don't need resolution
if echo "$path" | grep '^/' > /dev/null ; then
  printf '%s\n' "$path"
  exit 0
fi

#Resolve for each occurrence of ".." at the beginning of the given path.
#For performance, don't worry about ".." in the middle of the path.
while true
do
  case "$path" in
    ..*)
      if [ "$cwd" = '/' ]; then
        printf 'Invalid relative path\n' >&2
        exit 1
      fi
      if [ "$path" = '..' ]; then
        path=
      else
        path=`echo "$path" | sed 's;^\.\./;;'`
      fi
      cwd=`dirname $cwd`
      ;;
    *)
      break
      ;;
  esac
done

cwd=`echo "$cwd" | sed 's;/$;;'`
if [ -z "$path" ]; then
  if [ -z "$cwd" ]; then
    cwd='/'
  fi
  printf '%s\n' "$cwd"
else
  printf '%s/%s\n' "$cwd" "$path"
fi

该解决方案是为 Bourne Shell 编写的,以实现可移植性。我将其放在名为“respath.sh”的脚本中。

该脚本可以这样使用:

respath.sh '/path/to/file'

或者像这样

respath.sh '/relative/path/here' '/path/to/resolve/relative/to'

该脚本使用第二个参数中的路径作为起点来解析第一个参数中的路径。如果仅提供第一个参数,则脚本将解析相对于当前工作目录的路径。

相关内容