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

下面是一些调试信息:

$ which readlink; readlink -f
/usr/bin/readlink
readlink: illegal option -f
usage: readlink [-n] [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
}

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

其他回答

Echo $(cd $(dirname file1);pwd - p)

开始更新

This is such a frequent problem that we have put together a Bash 4 library for free use (MIT License) called realpath-lib. This is designed to emulate readlink -f by default and includes two test suites to verify (1) that it works for a given unix system and (2) against readlink -f if installed (but this is not required). Additionally, it can be used to investigate, identify and unwind deep, broken symlinks and circular references, so it can be a useful tool for diagnosing deeply-nested physical or symbolic directory and file problems. It can be found at github.com or bitbucket.org.

最后更新

另一个非常紧凑和高效的解决方案,它只依赖于Bash:

function get_realpath() {

    [[ ! -f "$1" ]] && return 1 # failure : file does not exist.
    [[ -n "$no_symlinks" ]] && local pwdp='pwd -P' || local pwdp='pwd' # do symlinks.
    echo "$( cd "$( echo "${1%/*}" )" 2>/dev/null; $pwdp )"/"${1##*/}" # echo result.
    return 0 # success

}

这还包括一个环境设置no_symlinks,它提供了将符号链接解析到物理系统的能力。只要no_symlinks被设置为某个值,即no_symlinks='on',那么symlinks将被解析为物理系统。否则将应用它们(默认设置)。

这应该可以在任何提供Bash的系统上工作,并将返回一个与Bash兼容的退出代码用于测试。

真正的平台独立也是r -online

readlink(){ RScript -e "cat(normalizePath(commandArgs(T)[1]))" "$1";}

要实际模拟readlink -f <path>,需要使用$2而不是$1。

我个人做了一个叫realpath的脚本,看起来有点像:

#!/usr/bin/env python
import os, sys
print(os.path.realpath(sys.argv[1]))

Readlink -f做两件事:

它沿着符号链接序列迭代,直到找到一个实际的文件。 它返回该文件的规范化名称。,它的绝对路径名。

如果您愿意,您可以构建一个shell脚本,使用普通readlink行为来实现相同的功能。举个例子。显然,你可以在自己的脚本中插入这个,你想调用readlink -f

#!/bin/sh

TARGET_FILE=$1

cd `dirname $TARGET_FILE`
TARGET_FILE=`basename $TARGET_FILE`

# Iterate down a (possible) chain of symlinks
while [ -L "$TARGET_FILE" ]
do
    TARGET_FILE=`readlink $TARGET_FILE`
    cd `dirname $TARGET_FILE`
    TARGET_FILE=`basename $TARGET_FILE`
done

# Compute the canonicalized name by finding the physical path 
# for the directory we're in and appending the target file.
PHYS_DIR=`pwd -P`
RESULT=$PHYS_DIR/$TARGET_FILE
echo $RESULT

注意,这并不包括任何错误处理。特别重要的是,它不检测符号链接循环。一种简单的方法是计算循环的次数,如果碰到一个不太可能的大数字(比如1000),就会失败。

edit使用pwd -P而不是$ pwd。

注意,这个脚本希望被称为。/script_name文件名,不使用-f,如果你想能够像GNU readlink一样使用-f文件名,将$1更改为$2。