상대 파일 경로의 절대 경로를 가져오는 bash에 내장 명령이 있습니까?

상대 파일 경로의 절대 경로를 가져오는 bash에 내장 명령이 있습니까?

외부 명령을 사용하여 realpath파일의 절대 경로를 얻을 수 있습니다.

realpath tmp/toto

반품

/home/john/tmp/toto

bash내장 함수를 사용하여 동일한 효과를 얻을 수 있나요 ?

답변1

쉘에는 bash상대 경로명이 주어지면 절대 경로를 명시적으로 얻는 기본 제공 방법이 없습니다.

zsh쉘 에서는 다음을 수행할 수 있습니다.

pathname=../../home/kk/.zshenv
print -r -- $pathname:P

그리고 반환합니다 /home/kk/.zshenv(가능한 경우 유사한 방식으로 모든 기호 링크도 해결된다는 점에 유의하세요 realpath()).

에서는 bash디렉토리가 아닌 경로 이름을 지정할 수 있으며 상위 디렉토리에 대한 검색 액세스 권한이 있다고 가정하면 다음을 사용하십시오.

$ pathname=../../home/kk/.zshenv
$ ( OLDPWD=- CDPATH= cd -P -- "${pathname%/*}" && printf '%s/%s\n' "$PWD" "${pathname##*/}" )
/home/kk/.zshenv

즉, 파일이 임시로 저장된(하위 쉘에) 디렉토리는 해당 값 과 경로 이름의 파일 이름 부분을 cd사용하여 절대 경로 이름을 구성하는 데 사용됩니다 . 부품 을 특별하게 취급하는 것은 피해야 합니다 $PWD. 디렉터리 자체의 기호 링크 구성 요소를 해결하는 부작용이 있습니다. 그러나 파일 자체가 심볼릭 링크라면 ( s 수정자 와 달리) 해결되지 않습니다 .-Pcd..zsh:P

우리는 대신 를 사용하여 이 문제를 OLDPWD해결하기 시작했습니다 (이 트릭은 작동 하지만 다른 모든 구현에서는 작동하지 않습니다).-cd -P -- -chdir($OLDPWD)chdir("-")bashsh

디렉토리 경로가 더 쉽습니다.

$ pathname=../../home/kk
$ ( OLDPWD=- CDPATH= cd -P -- "$pathname" && pwd )
/home/kk

편의상 이는 분명히 쉘 함수에 포함될 수 있습니다.

myrealpath () (
    if [[ -d $1 ]]; then
        OLDPWD=- CDPATH= cd -P -- "$1" && pwd
    else
        OLDPWD=- CDPATH= cd -P -- "${1%/*}" && printf '%s/%s\n' "$PWD" "${1##*/}"
    fi
)

(호출 셸의 작업 디렉터리가 변경되는 것을 방지하기 위해 전체 함수가 하위 셸에 정의되어 있습니다.)

이 기능을 테스트해 보세요:

$ myrealpath ../../home/kk
/home/kk
$ myrealpath ../../home/kk/.zshenv
/home/kk/.zshenv

운영 체제에 따라 매개 변수 없이 함수를 사용하면 현재 디렉터리의 절대 경로가 반환되거나 오류가 발생합니다. 향후 릴리스에서는 오류가 POSIX 요구 사항이 되므로 bash이는 모든 시스템의 버그가 될 수 있습니다 .cd ''

답변2

Bash에는 로드 가능한 확장 기능이 함께 제공됩니다 realpath. bash-4.4는 기본적으로 설치되어야 하므로 다음을 수행할 수 있어야 합니다.

BASH_LOADABLES_PATH=${BASH_LOADABLES_PATH:-/usr/local/lib/bash:/usr/lib/bash}
enable -f realpath realpath
realpath ..
help realpath

활성화되면 각 로드 가능한 명령은 추가 포크/실행 오버헤드가 없고 bash 환경을 조작할 수 있는 기능(예를 들어 loadable 에서 제공하는 경우)이 없는 "실제" 내장 명령이 됩니다 mypid.

-f옵션은 로드 가능한 확장 바이너리에 대한 경로를 지정합니다. 예상 위치에 없거나 배포판이 올바르게 설정하지 않은 경우 이 변수를 BASH_LOADABLES_PATH확장이 포함된 디렉터리(또는 -f로드 가능한 디렉터리)로 설정해야 합니다. 올바르게 설정했다면 위의 첫 번째 줄은 필요하지 않습니다.

그러한 확장이 필요하지만 필요하지 않은 이식 가능한 스크립트를 작성할 때 어쨌든 @Kusalananda의 라인을 따라 래퍼 함수를 ​​사용하여 외부(예 : readlink또는realpath핵심 도구).


  1. 이 확장은 bash-2.05부터 사용할 수 있지만 bash-4.4 이전에는 확장이 기본적으로 컴파일 및 설치되지 않았습니다.이렇게 하는 것은 쉽습니다작동하는 빌드 환경(C 컴파일러 등)이 있는 경우. 배포판에는 확장이 포함될 수도 있고 포함되지 않을 수도 있습니다. 불행하게도 RHEL 8(따라서 CentOS 8)은 로드 가능한 확장이 의도적으로 제거된 bash-4.4를 빌드합니다.

답변3

나는 다음을 제안합니다. 이는 Linux가 아닌 운영 체제(AIX 포함)에서 작동할 가능성이 높습니다. 절대 경로(즉, 시작부터의 경로 /)를 계산하려면 다음을 수행하세요.

abspath() {
  [[ $1 = /* ]] && printf "%s\n" "$1" || printf "%s\n" "$PWD/$1"
}

표준 경로(예: 모든 기호 링크가 확장된 경로)의 경우:

canonical_path() {
  perl -mCwd -le ' print Cwd::abs_path $ARGV[0] ' -- "$1"
}

에 대한 호출을 포함하여 다른 가능한 솔루션에 대해 테스트할 때 realpath마지막 경로 구성 요소가 있는지 여부와 마지막 경로 구성 요소가 심볼릭 링크인지 여부에 따라 상당한 차이가 있음을 알 수 있습니다.

답변4

Ubuntu와 같은 일부 시스템에는 "realpath" 명령이 있습니다. 시도해 볼 수도 realpath ~/foo.txt있고 그런 결과가 나올 수도 있으며 /home/user/foo.txt, 그런 다음 basedir파일 이름을 자르는 데 사용할 수 있습니다.

관련 정보