在 zsh 中获取脚本绝对路径的 Unix 可移植方法?

在 zsh 中获取脚本绝对路径的 Unix 可移植方法?

(zsh) 脚本确定其绝对路径的便携式1方法是什么?

在Linux上我使用类似的东西

mypath=$(readlink -f $0)

...但这不是便携式的。 (例如,readlink达尔文无法识别该-f标志,也没有任何等效标志。)(此外,readlink不可否认,为此使用是一个看起来相当晦涩难懂的黑客行为。)

有什么更便携的方式吗?


1也就是说,可跨 Unix 系列操作系统移植。

答案1

在 zsh 中您可以执行以下操作:

mypath=${0:a}

或者,获取脚本所在的目录:

mydir=${0:a:h}

关于历史扩展修饰符的 Zsh 文档,如果安装了信息文档,man zshexpn则在本地可见。info -f zsh -n Modifiers

答案2

对于zsh,它只是:

mypath=$0:A

或者

mypath=$0:P

在较新的版本中(请参阅手册了解它们有何不同的详细信息)。

现在对于其他 shell,虽然realpath()readlink()是标准函数(后者是系统调用),realpathreadlink不是标准命令,尽管某些系统具有其中之一或两者都有不同的行为和功能集。

通常,为了可移植性,您可能需要求助于perl

abs_path() {
  perl -MCwd -le '
    for (@ARGV) {
      if ($p = Cwd::abs_path $_) {
        print $p;
      } else {
        warn "abs_path: $_: $!\n";
        $ret = 1;
      }
    }
    exit $ret' "$@"
}

readlink -frealpath()(GNU ) 相比,它的行为更像是 GNU,readlink -e因为只要文件的目录名不存在,它就不会抱怨。

答案3

我已经使用它好几年了:

# The absolute, canonical ( no ".." ) path to this script
canonical=$(cd -P -- "$(dirname -- "$0")" && printf '%s\n' "$(pwd -P)/$(basename -- "$0")")

答案4

假设您确实指的是绝对路径,即来自根目录的路径:

case $0 in
  /*) mypath=$0;;
  *) mypath=$PWD/$0;;
esac

顺便说一句,这适用于任何 Bourne 风格的 shell。

如果您的意思是所有符号链接都已解析的路径,那就是另一回事了。readlink -f适用于 Linux(不包括一些精简的 BusyBox 系统)、FreeBSD、NetBSD、OpenBSD 和 Cygwin,但不适用于 OS/X、AIX、HP/UX 或 Solaris。如果有readlink,则可以循环调用它:

realpath () {
  [ -e "$1" ] || return
  case $1 in
    /*) :;;
    *) set "$PWD/$1";;
  esac
  while [ -L "$1" ]; do
    set "${1%/*}" "$(readlink "$1")"
    case $2 in
      /*) set "$2";;
      *) if [ -z "$1" ]; then set "/$2"; else set "$(cd "$1" && pwd -P)/$2"; fi;;
    esac
  done
  case $1 in
    */.|*/..) set "$(cd "$1" && pwd -P)";;
    */./*|*/../*) set "$(cd "${1%/*}" && pwd -P)/${1##*/}"
  esac
  realpath=$1
}

如果没有readlink,您可以用 来近似ls -n,但这仅在ls不破坏文件名中任何不可打印字符的情况下才有效。

poor_mans_readlink () {
  if [ -L "$1" ]; then
    set -- "$1" "$(LC_ALL=C command ls -n -- "$2"; echo z)"
    set -- "${2%??}"
    set -- "${2#*"$1 -> "}"
  fi
  printf '%s\n' "$1"
}

(额外的z情况是链接目标以换行符结尾,否则命令替换会耗尽。realpath顺便说一句,该函数不处理目录名的这种情况。)

相关内容