realpath가 심볼릭 링크를 해결하지 않도록 하려면 어떻게 해야 합니까?

realpath가 심볼릭 링크를 해결하지 않도록 하려면 어떻게 해야 합니까?

심볼릭 링크를 확인하지 않고 파일의 절대 경로를 반환하는 명령을 찾고 있습니다. 일반적으로 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/barCWD 경로는 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
}

관련 정보