readlink/realpath를 사용할 수 없는 경우 POSIX 셸에서 상대 경로를 해결하는 방법은 무엇입니까?

readlink/realpath를 사용할 수 없는 경우 POSIX 셸에서 상대 경로를 해결하는 방법은 무엇입니까?

readlink유틸리티를 사용할 수 없는 경우 realpath상대 경로를 확인하기 위해 POSIX 쉘 스크립트에서 무엇을 사용할 수 있습니까 (요즘에는 대부분 GNU coreutils에서 사용한다고 생각합니까?)

하나 있다realpath그러나 C는 기능합니다. 그럼 아마도 다른 하나일지도 몰라유용비밀리에 사용하시나요?

답변1

하나 있다realpath그러나 C는 기능합니다. 그럼 아마도 다른 하나일지도 몰라유용비밀리에 사용하시나요?

realpath내 머리로는 이러한 유틸리티 중 어느 것도 사양에서 이 기능을 참조하고 있는지 모르겠습니다 .

내가 아는 전부는시험디렉토리 항목의 경우경로 이름은 기존 디렉토리 항목으로 확인됩니다.1+x.

Peep에서의 구현대시(git.kernel.org), 그것은 사용lstat64/stat64.

이것은 디렉토리에 충분할 수 있습니다(시험-디경로명) 도착하다CD그 안으로 들어가서 확인된 경로 이름을 반환합니다.비밀번호.

~을 위한CD,CD 경로설정되지 않거나 비어 있어야 하며² 피연산자는 하이픈 빼기 기호가 아니어야 합니다."-"

([ -d "$1" ] && [ '-' != "$1" ] && CDPATH= cd -P -- "$1" && pwd -P)

예:디렉터리의 절대 경로, 정식 경로, 실제 경로 이름을 반환하거나, 디렉터리로 확인되지 않은 경우 null을 반환합니다.

경로 이름에서 하이픈 빼기 기호("-")를 제외하는 데 문제가 있는 경우 대안은 피연산자를 "./-"로 설정하는 것입니다.

1 참조시험² 참조CD 5단계 지침, 참조.cd "-" 피연산자


읽어보니 이미 아시는군요디렉토리 이름그리고기본 이름, 그리고 아마도 어떻게기호 링크가 끊어졌거나 존재하지 않는지 확인하십시오.  Unix & Linux, 그렇지 않다면 해당 답변의 맥락을 확인하여 관심이 있는지 확인하세요."시험구별 등의 사용법테스트 -d 경로 이름1. 종료 상태

답변2

질문을 게시한 후 다음과 같은 해결 방법을 생각해 냈습니다.

#!/bin/sh
realpath() (
    file=
    path=$1
    [ -d "$path" ] || {
        file=/$(basename -- "$path")
        path=$(dirname -- "$path")
    }
    {
        path=$(cd -- "$path" && pwd)$file
    } || exit $?
    printf %s\\n "/${path#"${path%%[!/]*}"}"
)

경고: 분명히 지금까지 이만큼 테스트할 수 없었습니다! 항상 피드백을 요청하세요. 혹시 보신 분 계시면 댓글 남겨주세요.

또한 다른 사람들도 이전에 같은 아이디어를 가지고 있었고 특히 극단적인 경우와 광범위한 테스트 후에 더 잘 해결했다고 확신합니다. 더 알고 계시다면 링크를 올려주세요.

위의 셸 기능은 realpathGNU coreutils를 대체합니다 realpath -s --.https://www.gnu.org/software/coreutils/manual/html_node/realpath-inplication.html. 이는 심볼릭 링크가 해결되지 않았음을 의미합니다. (상대 경로 해결에만 관심이 있는 경우에도 이는 필요하지 않습니다.)

  • #!/bin/sh
    

    Shebang을 POSIX 쉘로 사용하십시오.

  • realpath() (
    

    realpath() (...)대신 에 서브셸에서 함수를 실행 하면 realpath() {...}존재할 수 있는 file변수를 덮어쓰지 않습니다 path. (POSIX 쉘은 지역 변수를 지원하지 않습니다.)

  • file=
    path=$1
    

    변수를 정의합니다. 처음에는 인수에 의해 제공된 경로가 $1기존 디렉터리라고 가정합니다. (경로의 마지막 구성 요소가 제거하려는 경로의 반대 부분인 .또는 일 수 있기 때문에 이는 중요합니다.)..

  • [ -d "$path" ] || {
        file=/$(basename -- "$path")
        path=$(dirname -- "$path")
    }
    

    함수 인수가 이전에 가정한 대로 기존 디렉터리에 대한 경로가 아닌 경우 $pathQuote from 을 조정해야 합니다 man realpath.

    확인된 절대 파일 이름을 인쇄합니다. 마지막 구성 요소를 제외하고 모두 존재해야 합니다.

    $file따라서 ("마지막 구성 요소")가 실제로 기존 파일인지, 존재하지 않는 파일이나 폴더인지는 중요하지 않습니다. $path이제 삭제하고 결국 다시 첨부하겠습니다.

  • {
        path=$(cd -- "$path" && pwd)$file
    

    여기서 "트릭"이 발생합니다. 상대 경로를 해결하려면 해당 경로 cd를 구문 분석하고 pwd최종 디렉토리를 인쇄하는 데 사용하면 됩니다. 이 새로운 경로는 $path.2.6.3 명령 대체서브셸에서 실행합니다. $file마지막에 첨부됩니다.

  • } || exit $?
    

    {...}이 줄은 이전 줄의 변수 할당을 둘러싼 코드 블록의 이유입니다. 사용자가 잘못된 경로를 제공하는 경우(예: 마지막 구성 요소만 존재하지 않는 경우), cd(명령 대체 내에서) 실패하고 stderr에 오류 메시지를 인쇄해야 합니다(예: "...로 CD할 수 없습니다."). 오류 코드 > 0으로 종료합니다. 이는 명령 대체 서브쉘에 대한 오류 코드이기도 합니다. 이 오류 코드에 액세스하려면 $?변수 할당이 래핑됩니다 {...}. 따라서 {...}블록이 실패하면 함수를 종료하고 0이 아닌 동일한 오류 코드를 전파합니다.

  • printf %s\\n "/${path#"${path%%[!/]*}"}"
    

    //또는 존재하지 않는 /a것과 같은 극단적인 경우로 인해 결과는 또는 a입니다 . 그래서////a2.6.2 매개변수 확장$path최종 출력에 단일 슬래시를 추가하기 전에 에서 모든 선행 슬래시를 제거하는 데 사용됩니다 .

제가 실행한 몇 가지 테스트는 다음과 같습니다.

for path in / // /// . .. "$HOME/." "$HOME/.." "*" --help /tmp /notexisting
do
    if [ "$(realpath "$path")" != "$(/usr/bin/realpath -s -- "$path")" ]
    then
        printf %s\\n "$path"
    fi
done

관련 정보