[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
같은 동작을한다.
답변
readlink -f "$path"
편집자 주 : 위의 내용은 GNU readlink
및 FreeBSD / PC-BSD / OpenBSD readlink
에서는 작동하지만 10.11부터 OS X 에서는 작동 하지 않습니다 .
GNU readlink
는 -m
최종 대상이 존재하는지 여부에 관계없이 심볼릭 링크를 해결하기위한 추가 관련 옵션을 제공 합니다.
GNU coreutils 8.15 (2012-01-06) 이후로 위의 것보다 덜 애매하고 융통성 이있는 realpath 프로그램이 있습니다. 또한 같은 이름의 FreeBSD 유틸리티와 호환됩니다. 또한 두 파일 사이의 상대 경로를 생성하는 기능도 포함합니다.
realpath $path
[에 의해 코멘트에서 아래의 관리 또한 halloleo – danorton]
Mac OS X (최소 10.11.x 이상)의 readlink
경우 -f
옵션 없이 사용 하십시오 .
readlink $path
편집자 주 : 이것은 심볼릭 링크를 재귀 적으로 해결 하지 않으므로 궁극적 인 목표를 보고하지 않습니다 . 예를 들어, a
을 가리키는 symlink가을 b
가리키는 경우 c
, 이것은 단지보고 만하고 절대 경로b
로 출력되도록 보장하지는 않습니다 . 누락 된 기능 의 차이를 채우려면 OS X
에서 다음 명령을 사용하십시오 .perl
readlink -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"