[bash] 쉘 스크립트에서 심볼릭 링크를 해결하는 방법

절대 또는 상대 경로 (유닉스 계열 시스템에서)가 주어지면 중간 심볼릭 링크를 해결 한 후 대상의 전체 경로를 결정하고 싶습니다. ~ 사용자 이름 표기법을 동시에 해결하기위한 보너스 포인트.

대상이 디렉토리 인 경우 디렉토리에 chdir () 한 다음 getcwd ()를 호출 할 수 있지만 C 도우미를 작성하는 대신 쉘 스크립트 에서이 작업을 수행하고 싶습니다. 불행히도, 쉘은 사용자로부터 심볼릭 링크의 존재를 숨기려고 시도하는 경향이 있습니다 (OS X에서는 bash입니다).

$ ls -ld foo bar
drwxr-xr-x   2 greg  greg  68 Aug 11 22:36 bar
lrwxr-xr-x   1 greg  greg   3 Aug 11 22:36 foo -> bar
$ cd foo
$ pwd
/Users/greg/tmp/foo
$

위의 예제에서 tmp 디렉토리에서 실행될 때 resolve ( “foo”) == “/ Users / greg / tmp / bar”와 같은 resolve () 함수가 필요합니다.



답변

표준에 따르면 pwd -P심볼릭 링크가 해결 된 경로를 반환해야합니다.

C 함수 char *getcwd(char *buf, size_t size)에서이 unistd.h같은 동작을한다.

getcwd
암호


답변

readlink -f "$path"

편집자 주 : 위의 내용은 GNU readlinkFreeBSD / PC-BSD / OpenBSD readlink 에서는 작동하지만 10.11부터 OS X 에서는 작동 하지 않습니다 .
GNU readlink-m최종 대상이 존재하는지 여부에 관계없이 심볼릭 링크를 해결하기위한 추가 관련 옵션을 제공 합니다.

GNU coreutils 8.15 (2012-01-06) 이후로 위의 것보다 덜 애매하고 융통성 이있는 realpath 프로그램이 있습니다. 또한 같은 이름의 FreeBSD 유틸리티와 호환됩니다. 또한 두 파일 사이의 상대 경로를 생성하는 기능도 포함합니다.

realpath $path

[에 의해 코멘트에서 아래의 관리 또한 halloleodanorton]

Mac OS X (최소 10.11.x 이상)의 readlink경우 -f옵션 없이 사용 하십시오 .

readlink $path

편집자 주 : 이것은 심볼릭 링크를 재귀 적으로 해결 하지 않으므로 궁극적 인 목표를 보고하지 않습니다 . 예를 들어, a을 가리키는 symlink가을 b가리키는 경우 c, 이것은 단지보고 만하고 절대 경로b 로 출력되도록 보장하지는 않습니다 . 누락 된 기능 의 차이를 채우려면 OS X
에서 다음 명령을 사용하십시오 .
perlreadlink -f
perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"


답변

디렉토리를 원한다면 “pwd -P”가 작동하는 것 같지만 어떤 이유로 든 실제 실행 파일의 이름을 원한다면 도움이되지 않습니다. 내 해결책은 다음과 같습니다.

#!/bin/bash

# get the absolute path of the executable
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0")

# resolve symlinks
while [[ -h $SELF_PATH ]]; do
    # 1) cd to directory of the symlink
    # 2) cd to the directory of where the symlink points
    # 3) get the pwd
    # 4) append the basename
    DIR=$(dirname -- "$SELF_PATH")
    SYM=$(readlink "$SELF_PATH")
    SELF_PATH=$(cd "$DIR" && cd "$(dirname -- "$SYM")" && pwd)/$(basename -- "$SYM")
done


답변

내가 가장 좋아하는 것 중 하나는 realpath foo

realpath-정규화 된 절대 경로 이름을 반환

realpath는 모든 기호 링크를 확장하고 path로 명명 된 널 종료 문자열에서 '/./', '/../'및 추가 '/'문자에 대한 참조를 분석합니다.
       정규화 된 절대 경로 이름을 resolved_path로 명명 된 PATH_MAX 크기의 버퍼에 저장합니다. 결과 경로에는 기호 링크 '/./'또는
       '/../'구성 요소.


답변

readlink -e [filepath]

정확히 당신이 요구하는 것 같습니다-그것은 임의의 경로를 받아들이고 모든 심볼릭 링크를 해결하고 “실제”경로를 반환합니다-그리고 모든 시스템이 이미 가지고있는 “표준 * nix”


답변

또 다른 방법:

# Gets the real path of a link, following all links
myreadlink() { [ ! -h "$1" ] && echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : '.*-> \(.*\)$')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\([^/].*\)\$|$(dirname $1)/\1|"); }

# Returns the absolute path to a command, maybe in $PATH (which) or not. If not found, returns the same
whereis() { echo $1 | sed "s|^\([^/].*/.*\)|$(pwd)/\1|;s|^\([^/]*\)$|$(which -- $1)|;s|^$|$1|"; }

# Returns the realpath of a called command.
whereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\([^/].*\)\$|$(dirname ${SCRIPT_PATH})/\1|"; } 


답변

주어진 솔루션 중 일부를 종합하여 readlink가 대부분의 시스템에서 사용 가능하지만 다른 인수가 필요하다는 것을 알고 OSX 및 데비안에서 잘 작동합니다. BSD 시스템에 대해 잘 모르겠습니다. 조건 은 OSX에서만 [[ $OSTYPE != darwin* ]]제외 해야 -f합니다.

#!/bin/bash
MY_DIR=$( cd $(dirname $(readlink `[[ $OSTYPE == linux* ]] && echo "-f"` $0)) ; pwd -P)
echo "$MY_DIR"