在Linux上,readlink实用程序接受附加链接后面的选项-f。这似乎不适用于Mac和基于BSD的系统。等价的是什么?

下面是一些调试信息:

$ which readlink; readlink -f
/usr/bin/readlink
readlink: illegal option -f
usage: readlink [-n] [file ...]

当前回答

一种适合我的偷懒方式,

$ brew install coreutils
$ ln -s /usr/local/bin/greadlink /usr/local/bin/readlink
$ which readlink
/usr/local/bin/readlink
/usr/bin/readlink

其他回答

实现

安装酿造

按照https://brew.sh/上的说明操作

安装coreutils包

酿造安装coreutils

创建别名或符号链接

3 a。创建一个别名(每个用户)

您可以将别名放在~/中。bashrc,(~ /。Bash_profile,或者任何您习惯保存bash别名的地方。我个人把我的文件保存在~/.bashrc中

别名指向= greadlink

3 b。创建一个符号链接(系统范围)

ln -s /usr/local/bin/greadlink /usr/local/bin/readlink(来源:Izana)

这将在/usr/local/bin中创建一个符号链接,同时保留原始的readlink二进制文件。它可以工作,因为搜索readlink将返回2个结果。但是/usr/local/bin中的第二个将优先。

例如,哪个readlink

要撤消此更改,只需取消link /usr/local/bin/readlink

额外的工具

您可以为其他coreutil创建类似的别名或符号链接,例如gmv、gdu、gdf等等。但是要注意,GNU在mac机器上的行为可能会让其他习惯使用本机coreutils的人感到困惑,或者在mac系统上可能会以意想不到的方式表现。

解释

coreutils是一个brew包,用于安装GNU/Linux核心实用程序,这些实用程序对应于Mac OSX实现,以便您可以使用它们

你可能会发现mac osx系统上的程序或实用程序看起来与Linux coreutils(“核心实用程序”)相似,但它们在某些方面有所不同(例如具有不同的标志)。

这是因为Mac OSX对这些工具的实现是不同的。要获得原始的类似GNU/ linux的行为,您可以通过brew包管理系统安装coreutils包。

这将安装相应的核心实用程序,前缀为g。例如,对于readlink,你将找到相应的greadlink程序。

为了使readlink执行起来像GNU readlink (greadlink)实现,您可以在安装coreutils后创建一个简单的别名或符号链接。

您可能既需要可移植的纯shell实现,也需要单元测试覆盖率,因为此类情况的边缘情况的数量非常多。

查看我的项目在Github上的测试和完整代码。下面是实现的概要:

正如Keith Smith敏锐地指出的那样,readlink -f做了两件事:1)递归地解析符号链接,2)规范化结果,因此:

realpath() {
    canonicalize_path "$(resolve_symlinks "$1")"
}

首先,符号链接解析器实现:

resolve_symlinks() {
    local dir_context path
    path=$(readlink -- "$1")
    if [ $? -eq 0 ]; then
        dir_context=$(dirname -- "$1")
        resolve_symlinks "$(_prepend_path_if_relative "$dir_context" "$path")"
    else
        printf '%s\n' "$1"
    fi
}

_prepend_path_if_relative() {
    case "$2" in
        /* ) printf '%s\n' "$2" ;;
         * ) printf '%s\n' "$1/$2" ;;
    esac 
}

请注意,这是完整实现的略微简化版本。完整的实现为符号链接循环添加了一个小检查,并对输出进行了一些处理。

最后,规范化路径的函数:

canonicalize_path() {
    if [ -d "$1" ]; then
        _canonicalize_dir_path "$1"
    else
        _canonicalize_file_path "$1"
    fi
}   

_canonicalize_dir_path() {
    (cd "$1" 2>/dev/null && pwd -P) 
}           
        
_canonicalize_file_path() {
    local dir file
    dir=$(dirname -- "$1")
    file=$(basename -- "$1")
    (cd "$dir" 2>/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file")
}

差不多就是这样。简单到可以粘贴到您的脚本中,但也非常棘手,如果您依赖于任何用例中没有单元测试的代码,那就太疯狂了。

POSIX兼容的readlink -f实现POSIX shell脚本

https://github.com/ko1nksm/readlinkf

这是POSIX兼容的(没有bashism)。它既不使用readlink也不使用realpath。我已经通过与GNU readlink -f进行比较验证了它是完全相同的(参见测试结果)。它具有错误处理和良好的性能。可以安全地从readlink -f中替换。许可证是CC0,因此您可以将其用于任何项目。

此代码用于bat -core项目。

# POSIX compliant version
readlinkf_posix() {
  [ "${1:-}" ] || return 1
  max_symlinks=40
  CDPATH='' # to avoid changing to an unexpected directory

  target=$1
  [ -e "${target%/}" ] || target=${1%"${1##*[!/]}"} # trim trailing slashes
  [ -d "${target:-/}" ] && target="$target/"

  cd -P . 2>/dev/null || return 1
  while [ "$max_symlinks" -ge 0 ] && max_symlinks=$((max_symlinks - 1)); do
    if [ ! "$target" = "${target%/*}" ]; then
      case $target in
        /*) cd -P "${target%/*}/" 2>/dev/null || break ;;
        *) cd -P "./${target%/*}" 2>/dev/null || break ;;
      esac
      target=${target##*/}
    fi

    if [ ! -L "$target" ]; then
      target="${PWD%/}${target:+/}${target}"
      printf '%s\n' "${target:-/}"
      return 0
    fi

    # `ls -dl` format: "%s %u %s %s %u %s %s -> %s\n",
    #   <file mode>, <number of links>, <owner name>, <group name>,
    #   <size>, <date and time>, <pathname of link>, <contents of link>
    # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
    link=$(ls -dl -- "$target" 2>/dev/null) || break
    target=${link#*" $target -> "}
  done
  return 1
}

请参考最新的代码。它可能有些固定。

readlink的路径在我的系统和你的系统之间是不同的。请尝试指定完整路径:

/西南/ sbin / readlink -f

这个呢?

function readlink() {
  DIR="${1%/*}"
  (cd "$DIR" && echo "$(pwd -P)")
}