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)는 운영 체제 수준의 이전 프로세스에서 상속되거나 사용될 수 있습니다 chdir(2). 운영 체제(여기서는 "커널"을 의미함)는 물론 최종 디렉터리를 결정하기 위해 항상 모든 기호 링크를 확인합니다. 결과는 (디렉토리에 대한) 기호 링크가 아닌 디렉토리여야 합니다. 예를 들어, chdir(2)해결해야 할 심볼릭 링크가 너무 많으면 이전 시스템 호출( )이 오류를 반환할 수 있습니다. ELOOP따라서 운영 체제의 관점에서 볼 때 프로세스의 디렉터리가 아닌 CWD 디렉터리는 있을 수 없습니다. 운영 체제는 어디에도 심볼릭 링크 없이 항상 이를 실제 경로로 확인합니다.

셸이 완료되면 cd /tmp/test/barCWD 경로가 운영 체제에 의해 확인됩니다 /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
}

관련 정보