현재 작업 디렉토리 대신 파일 위치를 기반으로하는 상대 경로
이 질문에 이미 답변이 있습니다.
주어진:
some.txt
dir
|-cat.sh
내용이있는 cat.sh 사용 :
cat ../some.txt
그런 다음 ./cat.sh
내부 dir
실행 ./dir/cat.sh
은 dir
그렇지 않은 것과 동일한 수준에서 실행 하는 동안 잘 작동합니다 . 나는 이것이 다른 작업 디렉토리 때문일 것으로 예상합니다. ../some.txt
의 위치에 상대적인 경로를 만드는 것이 쉬웠 cat.sh
습니까?
원하는 것은 스크립트의 절대 경로 (를 통해 사용 가능 ${BASH_SOURCE[0]}
)를 얻은 다음이를 사용하여 상위 디렉토리를 가져오고 cd
스크립트 시작 부분 에이 경로를 가져 오는 것 입니다.
#!/bin/bash
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
cd "$parent_path"
cat ../some.text
이렇게하면 쉘 스크립트가 호출되는 위치와 독립적으로 작동합니다. 실행할 때마다 ./cat.sh
내부 에서 실행하는 것처럼 보입니다 dir
.
이 스크립트는 스크립트를 직접 호출하는 경우에만 작동합니다 (즉, 심볼릭 링크를 통하지 않음). 그렇지 않으면 스크립트의 현재 위치를 찾는 것이 조금 더 까다로워집니다.
@Martin Konecny의 대답 은 정답을 제공하지만 그가 언급했듯이 실제 스크립트가 다른 디렉토리 에있는 심볼릭 링크를 통해 호출되지 않는 경우에만 작동합니다 .
이 답변은 해당 경우를 다룹니다 . 스크립트가 심볼릭 링크 또는 심볼 체인을 통해 호출 될 때도 작동 하는 솔루션 :
Linux / GNUreadlink
솔루션 :
스크립트가 Linux 에서만 실행되어야 하거나 GNUreadlink
가에 있음을 알고 있는 경우 $PATH
,를 사용 readlink -f
하여 심볼릭 링크를 최종 대상 으로 편리하게 확인합니다 .
scriptDir=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
GNU readlink
에는 심볼릭 링크를 최종 대상의 전체 경로 -f
(( --canonicalize
), -e
( --canonicalize-existing
) 및 -m
( --canonicalize-missing
)) 로 확인하기위한 3 개의 관련 옵션이 있습니다 man readlink
.
이 시나리오에는 정의에 의한 대상이 존재하므로 세 가지 옵션 중 하나를 사용할 수 있습니다. -f
가장 잘 알려진 것이기 때문에 여기를 선택 했습니다.
다중 (유닉스 유사) 플랫폼 솔루션 ( POSIX 전용 유틸리티 세트 가있는 플랫폼 포함 ) :
스크립트가 다음과 같은 플랫폼에서 실행되어야하는 경우 :
이
readlink
유틸리티를하지만, 부족-f
, 예를 - (궁극적 인 목표에 심볼릭 링크를 해결하는 GNU의 의미에서) 옵션을 맥 OS .- macOS는 이전 버전 의 BSD 구현을 사용합니다
readlink
. 참고 FreeBSD의 / PC-BSD의 최신 버전은 어떻게 지원-f
.
- macOS는 이전 버전 의 BSD 구현을 사용합니다
심지어 가지고 있지 않다
readlink
없지만 POSIX 호환 유틸리티 (예 : HP-UX , @Charles Duffy)가 있습니다.
https://stackoverflow.com/a/1116890/45375 에서 영감을 얻은 다음 솔루션 은 주어진 심볼릭 링크를 루프의 최종 대상으로 확인하는 헬퍼 셸 함수를rreadlink()
정의 합니다.이 함수는 사실상 POSIX 호환 구현입니다. 암소 비슷한 일종의 영양readlink
의 -e
옵션 이며, 받는 사람과 비슷한 -f
궁극적 인 목표는해야한다는 것을 제외하고, 옵션 존재한다 .
참고 :이 함수는 bash
함수이며 POSIX 호환 옵션이있는 POSIX 유틸리티 만 사용된다는 점에서 POSIX 호환입니다. 이 기능의 버전은 자체가 POSIX 호환 쉘 코드 (대한 작성 /bin/sh
)를 참조하십시오 여기 .
readlink
사용 가능한 경우 (옵션없이) 사용됩니다. 대부분의 최신 플랫폼에서 마찬가지입니다.그렇지 않으면의 출력
ls -l
이 구문 분석되어 심볼릭 링크의 대상을 결정하는 유일한 POSIX 호환 방법입니다.
주의 사항 : 파일 이름이나 경로에 리터럴 하위 문자열이 포함되어 있으면 중단됩니다->
. 그러나 가능성은 낮습니다.
(부족한 플랫폼은readlink
은 여전히 심볼릭 링크를 해결하기 위해 POSIX가 아닌 다른 방법을 제공 할 수 있습니다. 예를 들어 @Charles Duffy는 기본 문자로 char 형식을find
지원하는 HP-UX의 유틸리티를 언급합니다. 간결성을 위해이 기능은 시도하지 않습니다. 그러한 경우를 감지하십시오.)%l
-printf
설치 가능한 유틸리티 (스크립트) 형식의 아래 함수 (추가 기능 포함)는 npm 레지스트리에서 찾을 수 있습니다 . Linux 및 macOS에서는 ; 다른 플랫폼 (이 있다고 가정 )에서는 수동 설치 지침을 따르십시오 .
rreadlink
[sudo] npm install -g rreadlink
bash
인수가 심볼릭 링크이면 최종 대상의 표준 경로가 반환됩니다. 그렇지 않으면 인수 자체의 표준 경로가 반환됩니다.
#!/usr/bin/env bash
# Helper function.
rreadlink() ( # execute function in a *subshell* to localize the effect of `cd`, ...
local target=$1 fname targetDir readlinkexe=$(command -v readlink) CDPATH=
# Since we'll be using `command` below for a predictable execution
# environment, we make sure that it has its original meaning.
{ \unalias command; \unset -f command; } &>/dev/null
while :; do # Resolve potential symlinks until the ultimate target is found.
[[ -L $target || -e $target ]] || { command printf '%s\n' "$FUNCNAME: ERROR: '$target' does not exist." >&2; return 1; }
command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path.
fname=$(command basename -- "$target") # Extract filename.
[[ $fname == '/' ]] && fname='' # !! curiously, `basename /` returns '/'
if [[ -L $fname ]]; then
# Extract [next] target path, which is defined
# relative to the symlink's own directory.
if [[ -n $readlinkexe ]]; then # Use `readlink`.
target=$("$readlinkexe" -- "$fname")
else # `readlink` utility not available.
# Parse `ls -l` output, which, unfortunately, is the only POSIX-compliant
# way to determine a symlink's target. Hypothetically, this can break with
# filenames containig literal ' -> ' and embedded newlines.
target=$(command ls -l -- "$fname")
target=${target#* -> }
fi
continue # Resolve [next] symlink target.
fi
break # Ultimate target reached.
done
targetDir=$(command pwd -P) # Get canonical dir. path
# Output the ultimate target's canonical path.
# Note that we manually resolve paths ending in /. and /.. to make sure we
# have a normalized path.
if [[ $fname == '.' ]]; then
command printf '%s\n' "${targetDir%/}"
elif [[ $fname == '..' ]]; then
# Caveat: something like /var/.. will resolve to /private (assuming
# /var@ -> /private/var), i.e. the '..' is applied AFTER canonicalization.
command printf '%s\n' "$(command dirname -- "${targetDir}")"
else
command printf '%s\n' "${targetDir%/}/$fname"
fi
)
# Determine ultimate script dir. using the helper function.
# Note that the helper function returns a canonical path.
scriptDir=$(dirname -- "$(rreadlink "$BASH_SOURCE")")
한 줄이면 괜찮습니다.
cat "`dirname $0`"/../some.txt
'programing' 카테고리의 다른 글
Notepad ++ 충돌시 코드 줄 손실 (0) | 2020.10.13 |
---|---|
따옴표와 큰 따옴표 이스케이프 (0) | 2020.10.12 |
템플릿 클래스와 클래스 템플릿의 차이점은 무엇입니까? (0) | 2020.10.12 |
문자열이 Scala의 Regex와 완전히 일치하는지 확인하는 방법은 무엇입니까? (0) | 2020.10.12 |
"visibility : collapse"와 "display : none"의 차이점 (0) | 2020.10.12 |