[macos] Mac에서 GNU의 readlink -f 동작을 얻으려면 어떻게해야합니까?

Linux에서 readlink유틸리티는 -f추가 링크를 따르는 옵션 을 허용합니다 . Mac 및 BSD 기반 시스템에서는 작동하지 않는 것 같습니다. 동등한 것은 무엇입니까?

디버그 정보는 다음과 같습니다.

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



답변

readlink -f 두 가지 일을한다 :

  1. 실제 파일을 찾을 때까지 일련의 심볼릭 링크를 반복합니다.
  2. 파일의 정규화 된 이름, 즉 절대 경로 이름을 반환합니다 .

원하는 경우 바닐라 읽기 링크 동작을 사용하여 동일한 작업을 수행하는 쉘 스크립트를 작성할 수 있습니다. 다음은 예입니다. 분명히 당신은 당신이 전화하고 싶은 자신의 스크립트에 이것을 삽입 할 수 있습니다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.

이 스크립트는 GNU readlink 와 같이 사용 하려면 ./script_name filename, no -f,로 변경 $1해야 $2합니다 -f filename.


답변

MacPorts 및 Homebrew는 (GNU readlink)를 포함 하는 coreutils 패키지를 제공합니다 greadlink. mackb.com의 Michael Kallweitt 게시물

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 버전은 더 짧아야합니다. 🙂


답변

나는 또 다른 구현에 더미 싫지만)는 필요 휴대용, 순수한 쉘 구현 하고, b)는 단위 테스트 범위 , 이런 일에 대한 가장자리 케이스의 수만큼 사소하지 않은 .

테스트 및 전체 코드 는 Github 프로젝트를 참조하십시오 . 다음은 구현의 개요입니다.

키이스 스미스 (Keith Smith)는 다음과 같이 지적한다 readlink -f. 1) 심볼릭 링크를 재귀 적으로 해결하고 2) 결과를 정규화한다

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

먼저 symlink resolver 구현 :

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
}

이것은 전체 구현 의 약간 단순화 된 버전입니다 . 전체 구현은 symlink주기에 대한 작은 검사를 추가 하고 출력을 약간 마사지합니다.

마지막으로 경로를 표준화하는 기능 :

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

그게 다야. 스크립트에 붙여 넣기는 간단하지만 사용 사례에 대한 단위 테스트가없는 코드에 의존하기에는 까다로울 수 있습니다.


답변

외부 의존성없이 거의 모든 곳에서 작동하는 펄의 간단한 1 라이너.

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


답변

  1. 사제 설치
  2. “brew install coreutils”를 실행하십시오.
  3. “greadlink -f path”를 실행하십시오.

greadlink는 -f를 구현하는 gnu readlink입니다. 당신은 macports 또는 다른 사람도 사용할 수 있습니다, 나는 homebrew를 선호합니다.


답변

나는 개인적으로 realpath라는 스크립트를 만들었습니다.

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