
심볼릭 링크를 확인하지 않고 파일의 절대 경로를 반환하는 명령을 찾고 있습니다. 일반적으로 realpath
이 작업을 잘 수행합니다.
$ mkdir /tmp/test; cd /tmp/test
$ mkdir foo
$ ln -s foo bar
$ realpath -se bar # good, this does not resolve the symlink
/tmp/test/bar
또한 심볼릭 링크 디렉터리 내부의 파일에서도 작동합니다.
$ touch foo/file
$ realpath -se bar/file # good, this does not resolve the symlink
/tmp/test/bar/file
그러나 현 이사가 실패하면 실패합니다.~이다심볼릭 링크 디렉토리
$ cd bar
$ pwd
/tmp/test/bar
$ realpath -se file # this fails, returning the target
/tmp/test/foo/file
$ realpath -se . # this also fails, returning the target
/tmp/test/foo
$ realpath -se /tmp/test/bar/file # yet this works
/tmp/test/bar/file
$ realpath -se /tmp/test/bar # and this works
/tmp/test/bar
왜 realpath
그렇게 행동할까요? (버그인가요?) realpath
심볼릭 링크를 절대 해결하지 못하게 하는 방법이 있나요, 아니면 사용해야 하는 다른 방법이 있나요?
답변1
프로세스의 현재 작업 디렉터리(CWD)는 이전 프로세스의 OS 수준에서 상속되거나 chdir(2)
. 물론 OS(여기서 "커널"을 의미함)는 항상 모든 심볼릭 링크를 확인하여 (디렉토리에 대한) 심볼릭 링크가 아닌 디렉토리여야 하는 최종 결과를 결정합니다. 예를 들어 이전 시스템 호출( ) 은 해결할 심볼릭 링크가 너무 많으면 chdir(2)
오류를 반환할 수 있습니다 . ELOOP
따라서 OS 관점에서 CWD는 프로세스의 디렉토리가 아닐 수 없습니다. OS는 항상 심볼릭 링크 없이 실제 경로를 확인합니다.
쉘이 완료되면 cd /tmp/test/bar
CWD 경로는 OS에 의해 /tmp/test/foo
. 예를 들어, Linux 시스템에서는 ls -l /proc/$$/cwd
커널에서 볼 수 있는 확인된 경로에 대한 링크를 표시합니다 /tmp/test/foo
.
bar
쉘이 여전히 프롬프트에 표시된다는 사실은 쉘이 다음을 기억하기 때문입니다.CD이전에 수행된 명령입니다. 동작은 쉘 종류에 따라 달라질 수 있습니다. 여기서는 bash를 가정하겠습니다. 따라서 내장된 pwd
(외부 /bin/pwd
명령은 아님) $PWD
변수와 그 사용은 $PS1
현재 디렉토리에 대해 사용자에게 "거짓말"을 합니다.
realpath
, 또는 셸에서 실행되는 모든 프로세스는 /bin/pwd
물론실제CWD는 /tmp/test/foo
. 따라서 이는 의 버그가 아니며 realpath
에 대한 특정 정보를 갖지 않습니다 bar
.
Kusalananda가 제안한 한 가지 가능한 어색한 방법은 변수를 재사용 하고 해당 인수가 아직 절대적이지 않은 경우에만 변수를 의 인수 $PWD
앞에 추가하는 것 입니다.realpath
여기에 예가 있습니다. 남용할 수 있는 방법이 없는지 잘 모르겠습니다. 예를 들어, 아래 함수는 대처할 수 있지만 $PWD
변수 자체는 bash 4.4.12(Debian 9)에서는 제대로 작동하지 않지만 경로에 줄바꿈 문자가 있는 경우 bash 5.0.3(Debian 10)에서는 제대로 작동합니다. 어딘가에 줄 바꿈이 있는 경우 유용하도록 -z
옵션도 추가해야 realpath
하지만 이 간단한 예에서는 옵션의 전체 구문 분석을 다시 구현하지 않을 것입니다.
myrealpathnofollowsym () {
for p in "$@"; do
if ! printf '%s' "$p" | grep -q -- '^/'; then
realpath -se "$PWD/$p"
else
realpath -se "$p"
fi
done
}