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


377

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

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

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

1
조금 늦었지만 질문에 사용중인 쉘에 대한 언급이 없습니다. readlink내장 명령이나 외부 명령 일 수 있으므로 관련이 있습니다.
0xC0000022L

1
아마도 그 차이를 설명 할 것입니다. 그래도 두 경우 모두 bash를 사용했다고 확신합니다.
troelskn 2012

1
Mac에서이 옵션이 왜 불법입니까?
CommaToast

3
나는 애플이 OS X이 더 많은 기본 리눅스 경로를 지원하고 이와 같은 것을 해결하기를 정말로 바란다. 그들은 아무것도 깨지 않고 할 수 있었습니까?
CommaToast

1
@CommaToast 글쎄, 그들은 Perl과 함께 제공되므로 ++ :-) .... Terminal.app을 열고 다음을 입력하십시오 : touch myfile ; ln -s myfile otherfile ; perl -MCwd=abs_path -le 'print abs_path readlink(shift);' otherfile... 내 경우에는 : / Users / cito / myfile`. 아래 답변에 추가했습니다. 건배.
G. Cito

답변:


181

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.


1
내가 알 수있는 한, 경로의 부모 디렉토리가 심볼릭 링크이면 작동하지 않습니다. 예 : if foo -> /var/cux인 경우 링크가 아니기 foo/bar때문에 해결 bar되지 않습니다 foo.
troelskn

1
아 예. 간단하지는 않지만 위 스크립트를 업데이트하여 처리 할 수 ​​있습니다. 그에 따라 답변을 편집 (실제로 다시 작성) 할 것입니다.
Keith Smith

글쎄, 링크는 경로의 어느 곳에 나있을 수 있습니다. 스크립트가 경로의 각 부분을 반복 할 수 있다고 생각하지만 조금 복잡해집니다.
troelskn

1
감사. 문제는 $ PWD가 우리가 수행 한 심볼릭 링크의 값을 기반으로 논리적 작업 디렉토리를 제공한다는 것입니다. 'pwd -P'로 실제 물리적 디렉토리를 얻을 수 있습니다. 파일 시스템의 루트까지 ".."를 쫓아서 계산해야합니다. 그에 따라 답변에서 스크립트를 업데이트합니다.
Keith Smith

12
훌륭한 솔루션이지만 공백포함 된 파일 또는 디렉토리 이름과 같이 이스케이프해야하는 경로를 제대로 처리하지 못합니다 . 즉, 사용 해결하려면 및 및 위의 코드에 적절한 장소에서합니다. cd "$(dirname "$TARGET_FILE")"TARGET_FILE=$(readlink "$TARGET_FILE")TARGET_FILE=$(basename "$TARGET_FILE")
mklement0

438

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

brew install coreutils

greadlink -f file.txt

bash 이외의 장소에서 readlink를 호출하는 경우 다른 해결책은 / usr / bin / readlink를 제거한 다음 / usr / local / bin / greadlink에 대한 링크를 작성하는 것입니다.
chinglun

8
a) 자신의 소프트웨어를 작성하지 않는 한 b) 다른 사람을 엉망으로 만들고 싶지 않다면하지 마십시오. 누구에게나 "그냥 작동"하는 방식으로 작성하십시오.
kgadek

14
@ching 대신에 이것을하십시오 .bashrc:export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
bfontaine

1
이 질문은 OS X 또는 BSD 시스템에서 이에 상응하는 것을 요구하지만, 그 대답은 아닙니다. Homebrew도 설치해야합니다. 또한 GNU Readlink와 별개로 많은 것들을 설치할 것입니다. 표준 OS X 설치용 스크립트를 작성하는 경우이 답변이 도움이되지 않습니다. 아무것도 설치하지 않고 OS X pwd -Preadlinkon 의 조합을 사용할 수 있습니다
Jason S

4
접두사없이 잘 작동하고 내 사용자가 쉽게 액세스 할 수있는 Mac의 GNU 및 기타 유틸리티를 했습니다 PATH. 위에서 시작했습니다 brew install <package> --default-names. 이 사이트의 질문에 대한 답변은 asker의 기술 요구 사항을 제외하고는 비슷한 상황에있을 때에도 다소 도움이되었습니다. topbug.net/blog/2013/04/14/…
Pysis

43

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


예, realpath실제로 내가 원하는 것입니다. 그러나 쉘 스크립트 에서이 기능을 얻으려면 바이너리를 컴파일 해야하는 것이 다소 어색한 것 같습니다.
troelskn

4
그렇다면 쉘 스크립트에서 Python one-liner를 사용하지 않는 이유는 무엇입니까? (한 줄로 전화하는 readlink것 자체와 크게 다르지 않습니까?)
Telemachus

3
python -c "import os,sys; print(os.path.realpath(os.path.expanduser(sys.argv[1])))" "${1}"같은 경로와 함께 작동'~/.symlink'
웨스 터너

@troelskin 나는 Perl, Python 이 "허용되었다"는 것을 몰랐다 ! ...이 경우에 나는 perl -MCwd=abs_path -le 'print abs_path readlink(shift);'나의 대답 에 추가 할 것이다 :-)
G. Cito

27

나는 또 다른 구현에 더미 싫지만)는 필요 휴대용, 순수한 쉘 구현 하고, 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")
}

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


3
이것은 POSIX가 아닙니다-POSIX가 아닌 local키워드를 사용합니다
go2null

이에 해당하지 readlink -f않으며,의 realpath. coreutils 공식이 설치되어 있고 ( greadlink사용 가능한 경우) Mac을 사용한다고 가정하면 ln -s /tmp/linkeddir ~/Documents; greadlink -f /tmp/linkeddir/..홈 디렉토리가 (이 해결 된 인쇄 /tmp/linkeddir적용하기 전에 링크를 ..부모 디렉토리의 심판),하지만 코드 생성 /private/tmp/으로 /tmp/linkeddir/..심볼릭 링크가 아니라 -d /tmp/linkeddir/..사실 등 cd /tmp/linkeddir/..으로 이동 /tmp누구의 정식 경로입니다 /private/tmp. realpath -L대신 코드가 작동합니다.
Martijn Pieters

27

외부 의존성없이 거의 모든 곳에서 작동하는 펄의 간단한 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)"

4
후행 줄 바꿈을 얻으려면 다음 -l과 같이 추가하십시오 .perl -MCwd -le 'print Cwd::abs_path shift' ~/non-absolute/file
pjvandehaar

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

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



이 명령을 일반 이름과 함께 사용해야하는 경우 bashrc에서 PATH = "/ usr / local / opt / coreutils / libexec / gnubin : $ PATH"와 같은 "gnubin"디렉토리를 PATH에 추가 할 수 있습니다.
Denis Trofimov

20

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

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

sys.argv[1]스크립트가 첫 번째 인수의 실제 경로를 인쇄하도록 하려면이를 변경해야합니다 . sys.argv[0]pyton 스크립트 자체의 실제 경로를 인쇄하므로 유용하지 않습니다.
Jakob Egger

17
다음에 대한 별칭 버전이 있습니다 ~/.profile.alias realpath="python -c 'import os, sys; print os.path.realpath(sys.argv[1])'"
jwhitlock

훌륭한 답변과 훌륭한 한 줄짜리 @jwhitlock. OP가 인용 한 이후 readlink -f가능한 -f플래그 를 지원하기 위해 @jwhitlock의 별칭을 수정 한 버전이 있습니다 . alias realpath="python -c 'import os, sys; print os.path.realpath(sys.argv[2] if sys.argv[1] == \"-f\" else sys.argv[1])'"
codesniffer

11

이건 어때?

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

이것은 나를 위해 작동하는 유일한 솔루션입니다. 내가 필요한 구문 분석 경로 등에 ../../../->/
keflavich

/usr/bin/예를 들어 alternatives시스템이 좋아 하는 심볼릭 링크가 있으면 작동하지 않습니다 .
akostadinov

개별 파일에는 작동하지 않으며 디렉토리에만 작동합니다. GNU readlink는 디렉토리, 파일, 심볼릭 링크 등에서 작동합니다.
코드 스니퍼

7

다음은 모든 Bourne 비교 가능한 쉘 에서 작동해야하는 휴대용 쉘 기능입니다 . 상대 경로 구두점 ".. 또는."을 해결합니다. 및 심볼릭 링크를 역 참조한다.

어떤 이유로 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"
}

또한 누군가 관심이있는 경우 100 % 순수 쉘 코드로 basename과 dirname을 구현하는 방법이 있습니다.

## 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##*/}"
}

내 Google 사이트 ( http://sites.google.com/site/jdisnard/realpath) 에서이 셸 코드의 업데이트 된 버전을 찾을 수 있습니다 .

편집 :이 코드는 2 절 (freeBSD 스타일) 라이센스의 조건에 따라 라이센스가 부여됩니다. 라이센스 사본은 내 사이트에 대한 위의 하이퍼 링크를 따라 찾을 수 있습니다.


bash 쉘의 Mac OS X Lion에서 real_path는 / path / to / filename 대신 / filename을 반환합니다.

@Barry OSX Snow Leopard에서도 마찬가지입니다. 더 나쁘고 연속적인 real_path () 호출은 출력을 연결합니다!
Dominique

@Dominique : 함수의 내부가 자체 하위 쉘에서 실행되지 않기 때문에 놀랍지 않습니다.
0xC0000022L

7

FreeBSDOSXstatNetBSD에서 파생 된 버전을 가지고 있습니다 .

포맷 스위치를 사용하여 출력을 조정할 수 있습니다 (위 링크의 매뉴얼 페이지 참조).

%  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

일부 OS X 버전에는 형식 옵션 이 stat 없을 수 -f%R있습니다. 이 경우 -stat -f%Y충분할 수 있습니다. 이 -f%Y옵션은 심볼릭 링크의 대상을 표시 -f%R하고 파일에 해당하는 절대 경로 이름을 표시합니다.

편집하다:

Perl을 사용할 수 있다면 (Darwin / OS X는 최신 버전으로 설치됨 perl) :

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

작동합니다.


2
이것은 FreeBSD 10에서는 사실이지만 OS X 10.9에서는 그렇지 않습니다.
Zanchey

잘 잡았습니다. 매뉴얼 페이지는 통계 인용은 OS / X 10.9입니다. R옵션을 사용하는 -f%이 없습니다. 아마도 stat -f%Y원하는 출력을 제공한다. 답을 조정하겠습니다. 이 stat도구는 버전 4.10의 FreeBSD와 버전 1.6의 NetBSD에 나타났습니다.
G. Cito

10.15에서 Perl 명령이 올바르게 작동하지 않습니다. 현재 디렉토리에 파일을 제공하고 파일없이 현재 디렉토리를 제공합니다.
코드 스니퍼

7

이 문제를 해결하고 Homebrew 또는 FreeBSD가 설치된 Mac에서 readlink 기능을 활성화하는 가장 쉬운 방법은 'coreutils'패키지를 설치하는 것입니다. 특정 Linux 배포판 및 기타 POSIX OS에서도 필요할 수 있습니다.

예를 들어 FreeBSD 11에서는 다음을 호출하여 설치했습니다.

# pkg install coreutils

Homebrew가 설치된 MacOS에서 명령은 다음과 같습니다.

$ brew install coreutils

왜 다른 답변이 그렇게 복잡한 지 잘 모르겠습니다. 파일이 다른 위치에 있지 않고 아직 설치되지 않았습니다.


7
brew install coreutils --with-default-names더 구체적으로. 아니면 대신 "greadlink"로 끝나게됩니다.
Henk

2010 stackoverflow.com/a/4031502/695671 및 2012 stackoverflow.com/a/9918368/695671 의 답변 과 차이가 없습니다 . 문제는 실제로 Mac 및 BSD 기반 시스템에서 "..."입니다. 동등한가? " 나는 이것이 그 질문에 대한 좋은 대답이라고 생각하지 않습니다. 여러 가지 이유가 있지만 아무것도 설치할 수없는 Mac OS 시스템을 대상으로 할 수 있습니다. pwd -P매우 간단하지만 반복되는 답변을 포함하여 다른 답변 중에서도 사라져 버립니다.
Jason S

3

업데이트 시작

이것은 우리가 자주 사용하는 Bash 4 라이브러리 인 realpath-lib 라는 MIT 라이센스 (Library-Library)를 구성하는 빈번한 문제입니다 . 이것은 기본적으로 readlink -f 를 에뮬레이트하도록 설계되었으며 (1) 주어진 유닉스 시스템에서 작동하는지 (2) 설치된 경우 readlink -f 에 대해 검증하는 두 가지 테스트 스위트를 포함합니다 (그러나 필수는 아닙니다). 또한 심오한 깨진 심볼릭 링크 및 순환 참조를 조사, 식별 및 해제하는 데 사용될 수 있으므로 심하게 중첩 된 물리적 또는 기호 적 디렉토리 및 파일 문제를 진단하는 데 유용한 도구가 될 수 있습니다. 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무언가로 설정, 즉 no_symlinks='on'다음 심볼릭 링크는 물리적 시스템으로 해결 될 것입니다. 그렇지 않으면 적용됩니다 (기본 설정).

이것은 Bash를 제공하는 모든 시스템에서 작동하며 테스트 목적으로 Bash 호환 종료 코드를 리턴합니다.


3

이미 많은 답변이 있지만 아무도 효과가 없었습니다. 그래서 이것이 지금 사용하고 있습니다.

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

1
$target경로 인 경우 작동하지 않으며 파일 인 경우에만 작동합니다.
MaxGhost

3

나를 위해 작동하는 게으른 방법,

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

1

결코 늦지 않는 것이 낫습니다. Fedora 스크립트가 Mac에서 작동하지 않기 때문에이를 구체적으로 개발하게되었습니다. 문제는 종속성과 Bash입니다. 맥에는 그것들이 없거나, 있다면 다른 곳 (또 다른 길)에 있습니다. 크로스 플랫폼 Bash 스크립트의 종속성 경로 조작은 두통이 많고 최악의 경우 보안 위험이 있으므로 가능하면 사용하지 않는 것이 가장 좋습니다.

아래의 get_realpath () 함수는 단순하고 Bash 중심이며 종속성이 필요하지 않습니다. 나는 Bash 내장 에코CD 만 사용합니다. . 또한 모든 단계에서 테스트되고 오류 조건을 반환하므로 상당히 안전합니다.

심볼릭 링크를 따르지 않으려면 스크립트 앞에 set -P 를 넣으십시오. 그렇지 않으면 cd 는 기본적으로 심볼릭 링크를 해결합니다. {absolute | 파일 인수로 테스트되었습니다. 친척 | symlink | local}이며 파일의 절대 경로를 반환합니다. 지금까지 우리는 아무런 문제가 없었습니다.

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

}

이것을 다른 함수 get_dirname, get_filename, get_stemname 및 validate_path와 결합 할 수 있습니다. 이들은 GitHub 저장소에서 realpath-lib 로 찾을 수 있습니다 (전체 정보-제품이지만 제한없이 커뮤니티에 무료로 제공)로 찾을 수 있습니다. 또한 교육 도구 역할을 할 수 있습니다-잘 문서화되어 있습니다.

우리는 소위 '현대 배쉬'관행을 적용하기 위해 최선을 다했지만 배쉬는 큰 주제이며 항상 개선의 여지가있을 것이라고 확신합니다. Bash 4 이상이 필요하지만 이전 버전이 여전히 남아 있으면 이전 버전과 작동하도록 만들 수 있습니다.


1

내 작업은 macOS뿐만 아니라 BSD Linux가 아닌 사람들도 사용하기 때문에 빌드 스크립트에서 이와 같은 별칭을 사용하도록 선택했습니다 ( 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

나는 정말로 "글로벌"하고 다른 사람들을 확인해야한다고 생각하지만 ... 아마도 80/20 마크에 가깝습니다.


1

설명

coreutils는 brewMac OSX 구현에 해당하는 GNU / Linux 핵심 유틸리티를 설치 하는 패키지입니다.

Mac osx 시스템에서 Linux coreutils ( "Core Utilities")와 비슷하지만 다른 방식으로 플래그가 다른 프로그램이나 유틸리티를 찾을 수 있습니다.

이러한 도구의 Mac OSX 구현이 다르기 때문입니다. 원래 GNU / Linux와 유사한 동작을 얻으려면 패키지 관리 시스템을 coreutils통해 패키지를 설치할 수 있습니다 brew.

이 접두사로 해당 핵심 유틸리티를 설치합니다 g. 예를 들어 readlink, 해당 greadlink프로그램 을 찾을 수 있습니다.

만들기 위하여 readlink는 GNU처럼 수행 readlink( greadlink당신이로 coreutils를 설치 한 후) 구현, 당신은 간단한 별칭을 만들 수 있습니다.

이행

  1. 추출 설치

https://brew.sh/ 의 지침을 따르십시오.

  1. coreutils 패키지 설치

brew install coreutils

  1. 별명 작성

~ / .bashrc, ~ / .bash_profile 또는 bash 별명을 유지하는 데 사용되는 곳에 별칭을 배치 할 수 있습니다. 나는 ~ / .bashrc에 개인적으로 내 것을 유지

alias readlink=greadlink

gmv, gdu, gdf 등과 같은 다른 coreutils에 대해 유사한 별명을 작성할 수 있습니다. 그러나 Mac 컴퓨터의 GNU 동작은 기본 coreutils 작업에 익숙한 다른 사람과 혼동되거나 mac 시스템에서 예기치 않은 방식으로 동작 할 수 있습니다.


0

OS X 용과 동일한 결과를 제공 할 수 있는 realpath 유틸리티를 작성 했습니다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


MacPorts를 사용하는 경우 다음 명령을 사용하여 설치할 수 있습니다 sudo port selfupdate && sudo port install realpath..


0

실제로 플랫폼 독립적 인 사람도이 R-onliner 일 것입니다

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

실제로 모방하려면 readlink -f <path>$ 1 대신 $ 2를 사용해야합니다.


R은 기본적으로 거의 모든 시스템에 존재하지 않습니다. Mac에서는 아직 (10.15 현재)이 질문에 관한 것입니다.
코드 스니퍼

0

POSIX readlink -f쉘 스크립트를위한 POSIX 호환 구현

https://github.com/ko1nksm/readlinkf

이것은 POSIX를 준수합니다 (bashism 없음). 나도 사용하지 readlink않습니다 realpath. GNU와 비교하여 정확히 동일한 지 확인했습니다 readlink -f( 테스트 결과 참조 ). 오류 처리 및 성능이 우수합니다. 에서 안전하게 교체 할 수 있습니다 readlink -f. 라이센스는 CC0이므로 모든 프로젝트에 사용할 수 있습니다.

# POSIX compliant version
readlinkf_posix() {
  [ "${1:-}" ] || return 1
  target=$1 max_symlinks=10 CDPATH=''

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

  cd -P . 2>/dev/null || return 1
  while [ "$max_symlinks" -gt 0 ] && max_symlinks=$((max_symlinks - 1)); do
    if [ ! "$target" = "${target%/*}" ]; then
      cd -P "${target%/*}/" 2>/dev/null || break
      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
}

최신 코드를 참조하십시오. 일부 고정되어있을 수 있습니다.


-2

Perl에는 readlink 기능이 있습니다 (예 : 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

5
재귀 없음, 절대 경로 없음-옵션이 readlink없는 것과 동일 -f하므로 readlink직접 사용할 수도 있습니다.
mklement0

-2

@Keith Smith의 답변은 무한 루프를 제공합니다.

다음은 SunOS에서만 사용하는 답변입니다 (SunOS는 POSIX 및 GNU 명령이 너무 많습니다).

$ PATH 디렉토리 중 하나에 넣어야하는 스크립트 파일입니다.

#!/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"


-5

readlink 경로는 내 시스템과 귀하의 시스템에 따라 다릅니다. 전체 경로를 지정하십시오.

/sw/sbin/readlink -f


1
/ sw / sbin과 / usr / bin의 차이점은 정확히 무엇입니까? 두 바이너리가 다른 이유는 무엇입니까?
troelskn 2016 년

4
Aha .. fink에는 readlinkgnu 호환되는 교체품이 포함되어 있습니다 . 알고있는 것이 좋지만 다른 사람들의 컴퓨터에서 스크립트를 실행해야하기 때문에 문제를 해결하지 못하므로,이를 위해 핀을 설치하도록 요구할 수 없습니다.
troelskn

원래 질문에 대답하지 않았습니다. 답을 다시 쓰십시오.
Jaime Hablutzel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.