代码之家  ›  专栏  ›  技术社区  ›  troelskn

我如何在Mac上获得GNU readlink-f的行为?[关闭]

  •  450
  • troelskn  · 技术社区  · 16 年前

    readlink -f

    $ which readlink; readlink -f
    /usr/bin/readlink
    readlink: illegal option -f
    usage: readlink [-n] [file ...]
    
    26 回复  |  直到 14 年前
        1
  •  469
  •   pravdomil tomyjwu    8 年前

    MacPorts和Homebrew提供了 greadlink

    brew install coreutils
    
    greadlink -f file.txt
    
        2
  •  196
  •   Benjamin W.    9 年前

    readlink -f 做两件事:

    1. 它沿着一系列符号链接迭代,直到找到一个实际的文件。

    如果你愿意,你可以构建一个使用vanilla readlink行为的shell脚本来实现同样的功能。这里有一个例子。显然,您可以将其插入到您自己的脚本中您想调用的位置

    #!/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,就会失败。

    pwd -P $PWD .

    ./script_name filename ,没有 -f $1 $2 -f filename

        3
  •  48
  •   sorin    9 年前

    realpath(3) os.path.realpath

    $ pwd
    /tmp/foo
    $ ls -l
    total 16
    -rw-r--r--  1 miles    wheel  0 Jul 11 21:08 a
    lrwxr-xr-x  1 miles    wheel  1 Jul 11 20:49 b -> a
    lrwxr-xr-x  1 miles    wheel  1 Jul 11 20:49 c -> b
    $ python -c 'import os,sys;print(os.path.realpath(sys.argv[1]))' c
    /private/tmp/foo/a
    

    #!/usr/bin/python
    
    import ctypes, sys
    
    libc = ctypes.CDLL('libc.dylib')
    libc.realpath.restype = ctypes.c_char_p
    libc.__error.restype = ctypes.POINTER(ctypes.c_int)
    libc.strerror.restype = ctypes.c_char_p
    
    def realpath(path):
        buffer = ctypes.create_string_buffer(1024) # PATH_MAX
        if libc.realpath(path, buffer):
            return buffer.value
        else:
            errno = libc.__error().contents.value
            raise OSError(errno, "%s: %s" % (libc.strerror(errno), buffer.value))
    
    if __name__ == '__main__':
        print realpath(sys.argv[1])
    

        4
  •  34
  •   JinnKo    10 年前

    perl -MCwd -e 'print Cwd::abs_path shift' ~/non-absolute/file
    

    将取消引用符号链接。

    readlinkf(){ perl -MCwd -e 'print Cwd::abs_path shift' "$1";}
    ABSPATH="$(readlinkf ./non-absolute/file)"
    
        5
  •  29
  •   Michael Kropat    12 年前

    你可能两者都需要 .

    my project on Github

    readlink -f

    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 
    }
    

    the full implementation .

    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")
    }
    

        6
  •  28
  •   Andrew    14 年前
    1. 安装自制程序

        7
  •  22
  •   neu242    5 年前

    #!/usr/bin/env python
    import os, sys
    print(os.path.realpath(sys.argv[1]))
    
        8
  •  15
  •   kevin.groat Peeech    7 年前

    function readlink() {
      DIR="${1%/*}"
      (cd "$DIR" && echo "$(pwd -P)")
    }
    
        9
  •  7
  •   G. Cito Marc    10 年前

    $ brew install coreutils
    $ ln -s /usr/local/bin/greadlink /usr/local/bin/readlink
    $ which readlink
    /usr/local/bin/readlink
    /usr/bin/readlink
    
        10
  •  7
  •   Avery Freeman    9 年前

    请遵循以下说明 https://brew.sh/

    brew install coreutils

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

    您可以将别名放在~/.bashrc、~/.bash_profile或任何您习惯保留bash别名的地方。我个人把我的放在~/.bashrc中

    alias readlink=greadlink

    ln -s /usr/local/bin/greadlink /usr/local/bin/readlink

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

    which readlink

    unlink /usr/local/bin/readlink

    其他工具

    brew 安装GNU/Linux核心实用程序的软件包,这些实用程序与Mac OSX实现相对应,以便您可以使用它们

    coreutils 酿造

    g readlink greadlink

    为了使 读取链接 ( 油性油墨

        11
  •  7
  •   Izana    6 年前

    FreeBSD OSX stat

    %  cd  /service
    %  ls -tal 
    drwxr-xr-x 22 root wheel 27 Aug 25 10:41 ..
    drwx------  3 root wheel  8 Jun 30 13:59 .s6-svscan
    drwxr-xr-x  3 root wheel  5 Jun 30 13:34 .
    lrwxr-xr-x  1 root wheel 30 Dec 13 2013 clockspeed-adjust -> /var/service/clockspeed-adjust
    lrwxr-xr-x  1 root wheel 29 Dec 13 2013 clockspeed-speed -> /var/service/clockspeed-speed
    % stat -f%R  clockspeed-adjust
    /var/service/clockspeed-adjust
    % stat -f%Y  clockspeed-adjust
    /var/service/clockspeed-adjust
    

    -f%R 格式选项。在这种情况下 -stat -f%Y -f%Y -f%R 显示了与文件对应的绝对路径名。

    perl

    perl -MCwd=abs_path -le 'print abs_path readlink(shift);' linkedfile.txt
    

        12
  •  6
  •   SamB som-snytt    14 年前

    # pkg install coreutils

    $ brew install coreutils

        13
  •  6
  •   yosefrow    5 年前

    如果由于某种原因您没有realpath(1)命令或readlink(1),这可能会被别名化。

    which realpath || alias realpath='real_path'
    

    real_path () {
      OIFS=$IFS
      IFS='/'
      for I in $1
      do
        # Resolve relative path punctuation.
        if [ "$I" = "." ] || [ -z "$I" ]
          then continue
        elif [ "$I" = ".." ]
          then FOO="${FOO%%/${FOO##*/}}"
               continue
          else FOO="${FOO}/${I}"
        fi
    
        ## Resolve symbolic links
        if [ -h "$FOO" ]
        then
        IFS=$OIFS
        set `ls -l "$FOO"`
        while shift ;
        do
          if [ "$1" = "->" ]
            then FOO=$2
                 shift $#
                 break
          fi
        done
        IFS='/'
        fi
      done
      IFS=$OIFS
      echo "$FOO"
    }
    

    ## http://www.opengroup.org/onlinepubs/000095399/functions/dirname.html
    # the dir name excludes the least portion behind the last slash.
    dir_name () {
      echo "${1%/*}"
    }
    
    ## http://www.opengroup.org/onlinepubs/000095399/functions/basename.html
    # the base name excludes the greatest portion in front of the last slash.
    base_name () {
      echo "${1##*/}"
    }
    

    http://sites.google.com/site/jdisnard/realpath

    编辑:

        14
  •  3
  •   AsymLabs    12 年前

    github.com 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='on'

        15
  •  3
  •   estani    9 年前

    readlink_f() {
      local target="$1"
      [ -f "$target" ] || return 1 #no nofile
    
      while [ -L "$target" ]; do
        target="$(readlink "$target")" 
      done
      echo "$(cd "$(dirname "$target")"; pwd -P)/$target"
    }
    
        16
  •  2
  •   clounie    7 年前

    sed

    ##
    # If you're running macOS, use homebrew to install greadlink/gsed first:
    #   brew install coreutils
    #
    # Example use:
    #   # Gets the directory of the currently running script
    #   dotfilesDir=$(dirname "$(globalReadlink -fm "$0")")
    #   alias al='pico ${dotfilesDir}/aliases.local'
    ##
    
    function globalReadlink () {
      # Use greadlink if on macOS; otherwise use normal readlink
      if [[ $OSTYPE == darwin* ]]; then
        greadlink "$@"
      else
        readlink "$@"
      fi
    }
    
    function globalSed () {
      # Use gsed if on macOS; otherwise use normal sed
      if [[ $OSTYPE == darwin* ]]; then
        gsed "$@"
      else
        sed "$@"
      fi
    }
    

    homebrew coreutils 依赖关系:

    if [[ "$OSTYPE" == "darwin"* ]]; then
      # Install brew if needed
      if [ -z "$(which brew)" ]; then 
        /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"; 
      fi
      # Check for coreutils
      if [ -z "$(brew ls coreutils)" ]; then
        brew install coreutils
      fi
    fi
    

        17
  •  2
  •   Koichi Nakashima    5 年前

    readlink -f

    https://github.com/ko1nksm/readlinkf

    readlink realpath (参见 test results 许可证为CC0,因此您可以将其用于任何项目。

    本规范在 bats-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
    }
    

        18
  •  1
  •   AsymLabs    12 年前

    echo$(cd$(目录名file1);pwd-P)

        19
  •  0
  •   user454322    10 年前

    回声 。它也相当安全,因为所有内容都会在每个阶段进行测试,并返回错误条件。

    如果你不想遵循符号链接,那么放 光盘

    function get_realpath() {
    
    if [[ -f "$1" ]]
    then
        # file *must* exist
        if cd "$(echo "${1%/*}")" &>/dev/null
        then
            # file *may* not be local
            # exception is ./file.ext
            # try 'cd .; cd -;' *works!*
            local tmppwd="$PWD"
            cd - &>/dev/null
        else
            # file *must* be local
            local tmppwd="$PWD"
        fi
    else
        # file *cannot* exist
        return 1 # failure
    fi
    
    # reassemble realpath
    echo "$tmppwd"/"${1##*/}"
    return 0 # success
    
    }
    

    realpath-lib (完全披露-这是我们的产品,但我们免费向社区提供,没有任何限制)。它也可以作为一种教学工具——它有很好的记录。

    我们已经尽力应用所谓的“现代Bash”实践,但Bash是一个很大的主题,我相信总会有改进的空间。它需要Bash 4+,但如果旧版本仍然存在,可以使其与旧版本一起工作。

        20
  •  0
  •   Holger Brandl    10 年前

    我写的 a realpath utility for OS X readlink -f .



    (jalcazar@mac tmp)$ ls -l a
    lrwxrwxrwx 1 jalcazar jalcazar 11  8月 25 19:29 a -> /etc/passwd
    
    (jalcazar@mac tmp)$ realpath a
    /etc/passwd
    


    sudo port selfupdate && sudo port install realpath .

        21
  •  0
  •   sunnz    5 年前

    真正的平台依赖者也是这个R-onliner

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

    readlink -f <path>

        22
  •  -2
  •   Community Mohan Dere    9 年前

    #!/usr/bin/env bash -e
    
    declare script=$(basename "$0")
    declare dirname=$(dirname "$0")
    declare scriptDir
    if [[ $(uname) == 'Linux' ]];then
        # use readlink -f
        scriptDir=$(readlink -f "$dirname")
    else
        # can't use readlink -f, do a pwd -P in the script directory and then switch back
        if [[ "$dirname" = '.' ]];then
            # don't change directory, we are already inside
            scriptDir=$(pwd -P)
        else
            # switch to the directory and then switch back
            pwd=$(pwd)
            cd "$dirname"
            scriptDir=$(pwd -P)
            cd "$pwd"
        fi
    fi
    

    readlink -f . $scriptDir $script

    pwd -P

        23
  •  -2
  •   scavenger    11 年前

    How do I copy symbolic links in Perl? ).这适用于大多数平台,包括OS X:

    perl -e "print readlink '/path/to/link'"
    

    $ mkdir -p a/b/c
    $ ln -s a/b/c x
    $ perl -e "print readlink 'x'"
    a/b/c
    
        24
  •  -3
  •   Carlos Nunez    10 年前

    #!/bin/sh
    ! (($#)) && echo -e "ERROR: readlink <link to analyze>" 1>&2 && exit 99
    
    link="$1"
    while [ -L "$link" ]; do
      lastLink="$link"
      link=$(/bin/ls -ldq "$link")
      link="${link##* -> }"
      link=$(realpath "$link")
      [ "$link" == "$lastlink" ] && echo -e "ERROR: link loop detected on $link" 1>&2 && break
    done
    
    echo "$link"
    
        25
  •  -5
  •   Quinn Taylor    16 年前

    stat -f %N $your_path