我怎样才能得到GNU的readlink的行为

在Linux上, readlink实用程序接受附加链接readlink的选项-f 。 这似乎不适用于Mac和可能的基于BSD的系统。 相当于什么?

这里有一些调试信息:

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

readlink -f做了两件事:

  • 它沿着一系列符号链接进行迭代,直到找到一个实际的文件。
  • 它返回该文件的规范化名称,即其绝对路径名。
  • 如果你愿意,你可以建立一个使用vanilla readlink行为的shell脚本来达到同样的效果。 这是一个例子。 很明显,你可以在你想要调用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
    

    请注意,这不包括任何错误处理。 特别重要的是,它不检测符号链接周期。 一个简单的方法是计算循环次数,如果碰到一个不可能的大数目,例如1,000,则失败。

    编辑使用pwd -P而不是$PWD

    请注意,如果您希望能够使用-f filename如GNU readlink),则此脚本预计将被称为./script_name filename ,否-f ,将$1更改$1 $2


    MacPorts和Homebrew提供了一个包含greadlink的coreutils包(GNU readlink)。 感谢Michael Kallweitt在mackb.com发表的文章。

    brew install coreutils
    
    greadlink -f file.txt
    

    您可能对realpath(3)或Python的os.path.realpath感兴趣。 这两个不完全一样; C库调用需要存在中间路径组件,而Python版本则不需要。

    $ 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
    

    我知道你说过你更喜欢比其他脚本语言更轻量级的东西,但是为了防止编译二进制文件变得难以忍受,可以使用Python和ctypes(可在Mac OS X 10.5上使用)来封装库调用:

    #!/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])
    

    具有讽刺意味的是,这个脚本的C版本应该更短。 :)

    链接地址: http://www.djcxy.com/p/9729.html

    上一篇: How can I get the behavior of GNU's readlink

    下一篇: How to detect the current directory in which I run my shell script?