Bash 스크립트가 전체 경로를 얻을 수 있는 신뢰성 높은 방법
전체 경로를 알아야 하는 Bash 스크립트가 있습니다.상대적이거나 펑키해 보이는 경로로 끝나지 않고 폭넓게 호환되는 방법을 찾고 있습니다.저는 Sh, csh 등이 아닌 Bash만 지원하면 됩니다.
지금까지 알아낸 것:
주소 내에서 Bash 스크립트의 소스 디렉토리를 가져오고 스크립트의 경로를 가져오는 데 사용되는 답변입니다.
dirname $0
(이것은 괜찮지만, 상대적인 패스를 되돌리는 경우가 있습니다)..
스크립트내의 디렉토리를 변경해, 패스가 계속 스크립트의 디렉토리를 가리키고 있는 경우, 이것은 문제가 됩니다.★★★★★★★★★★★★★★★.dirname
퍼즐의 일부가 될 것이다.OS X를 사용하는 Bash 스크립트 절대 경로에 대해 승인된 응답(OS X에 고유하지만 응답은 상관 없이 작동함)은 테스트되는 함수를 제공합니다.
$0
looks relative and if so will pre-pend 상대적으로 보이며, 상대적인 경우 프리펜드됩니다.$PWD
그러나 그 결과는 여전히 러 그러나, 스크립트는 그 overall 과 인 적 대 적 이 지 it 대 it to the) is, can have but it instance절 the script전포비 예를 들어 스크립트가t
in the directory 전화번호부에/usr/bin
and you're in 그리고 너는 안에 있다/usr
and you type 라고 입력합니다.bin/../bin/t
(예: 아니, 해, 건, 난, 합, 엔, 국 touted,), ( that it' convol (s run up endyes with you네,),다니그결,uted/usr/bin/../bin
를 스크립트의 디렉토리 경로로 지정합니다.잘 먹히긴 하지만...readlink
이 페이지의 솔루션은 다음과 같습니다.# Absolute path to this script. /home/user/bin/foo.sh SCRIPT=$(readlink -f $0) # Absolute path this script is in. /home/user/bin SCRIPTPATH=`dirname $SCRIPT`
★★★★★★★★★★★★★★★★★.
readlink
이 의 POSIX에 하고 있는 것 .GNUreadlink
어떤 이유로 BSD가 동작하지 않는 경우(BSD와 같은 시스템에 액세스 할 수 없습니다.
여러 가지 방법들이 있지만, 그들 모두 나름의 주의점이 있습니다.
어떤 방법이 더 좋을까요?여기서 "better"는 다음을 의미합니다.
- 내게 절대적인 경로를 알려주지
- 복잡한 방법으로 호출된 경우에도 펑키 비트를 제거합니다(위 #2의 주석 참조).(예: 적어도 적당히 경로를 정규화합니다.)
- Bash-isms 또는 가장 일반적인 *nix 시스템(GNU/Linux, BSD 및 OS X 등 BSD 유사 시스템)에 의존합니다.
- 가능하면 외부 프로그램을 호출하지 않습니다(Bash 내장 프로그램 선호 등).
- (갱신 완료, 경고해 주셔서 감사합니다)심볼링크를 해결할 필요는 없습니다(사실 그냥 놔두고 싶지만 그건 필수가 아닙니다).
내가 생각해낸 것은 다음과 같다(편집: sfstewman, levigroker, Kyle Strand 및 Rob Kennedy가 제공한 몇 가지 수정사항). 이는 나의 "더 나은" 기준에 대부분 부합하는 것 같다.
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
★★★SCRIPTPATH
은 특히 우회적인 것처럼 , 하다.SCRIPTPATH=`pwd`
공간 및 심볼링크를 적절하게 처리하기 위해 사용합니다.
리다이렉트 ( 「 「 」 )>/dev/null 2>&1
、 、 음 、 음 、 ) ( ? ) 、 where where where where where where where where where where(?)의(?) 합니다.cd
는, 의 「주변」을 이 있는 출력을 할 수 있습니다.$( ... )
캡처합니다.(디렉토리로 전환한 후에 디렉토리에도 덮어쓰기 되는 등).
또, 액세스 가능한 파일 시스템의 파일로부터 전혀 송신되지 않는 스크립트(완벽한 가능성)를 실행하는 등, 난해한 상황은, 거기에 대응하고 있지 않습니다(또는 지금까지 본 그 외의 회답은 없습니다).
--
후에cd
and ★★★★★★★★★★★★★★★★★★."$0"
가 「a」로 시작되는 입니다.-
.
realpath
명령어는 여기에 기재되어 있지 않습니다.내가 알기로는 그것은 널리 휴대할 수 있다.
초기 솔루션은 다음과 같습니다.
SCRIPT=$(realpath "$0")
SCRIPTPATH=$(dirname "$SCRIPT")
기호 링크를 원하는 대로 해결되지 않은 상태로 두려면:
SCRIPT=$(realpath -s "$0")
SCRIPTPATH=$(dirname "$SCRIPT")
를 얻는 은 Bash를 사용하는 입니다.cd
★★★★★★★★★★★★★★★★★」pwd
ABSOLUTE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
「」를 사용합니다.${BASH_SOURCE[0]}
$0
는, 가 「이러한 동작」으로서 되고 있는지 , 합니다.<name>
★★★★★★★★★★★★★★★★★」source <name>
.
오늘 이 문제를 다시 살펴봐야 했는데 스크립트 자체에서 Bash 스크립트의 소스 디렉토리를 가져옵니다.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
링크된 답변에는 스크립트 자체가 심볼 링크인 경우 등 더 많은 변종이 있습니다.
셸 스크립트의 절대 경로를 가져옵니다.
문구는 .-f
BSD/Mac OS X를 사용합니다.
서포트
- ./script로 시)
.
연산자로 표시됨) - 절대 경로 /path/to/script
- ./script와 같은 상대 경로.
- /path/syslog1/../syslog2/syslog3/../script
- symlink에서 호출할 때
- 경우( ) symblink( )
foo->dir1/dir2/bar bar->./../doe doe->script
- 발신자가 스크립트 이름을 변경한 경우
이 코드가 작동하지 않는 코너 케이스를 찾고 있습니다.알려주세요.
코드
pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
while([ -h "${SCRIPT_PATH}" ]); do
cd "`dirname "${SCRIPT_PATH}"`"
SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
done
cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
SCRIPT_PATH="`pwd`";
popd > /dev/null
echo "srcipt=[${SCRIPT_PATH}]"
echo "pwd =[`pwd`]"
알려진 이슈스
스크립트는 디스크 어딘가에 있어야 합니다.네트워크를 통해 전송해 주세요.PIPE에서 이 스크립트를 실행하려고 하면 동작하지 않습니다.
wget -o /dev/null -O - http://host.domain/dir/script.sh |bash
엄밀히 말하면, 그것은 정의되어 있지 않다.사실상, 이것을 탐지할 수 있는 제정신적인 방법은 없다.(공동 프로세스는 부모 환경에 액세스할 수 없습니다.)
용도:
SCRIPT_PATH=$(dirname `which $0`)
which
은 셸되었을 때 를 출력합니다.
dirname
는, 파일명으로부터 디렉토리 이외의 서픽스를 삭제합니다.
따라서 경로가 지정되었는지 여부에 관계없이 스크립트의 전체 경로가 지정됩니다.
Linux 시스템에는 기본적으로 realpath가 설치되어 있지 않기 때문에 다음 기능이 작동합니다.
SCRIPT="$(readlink --canonicalize-existing "$0")"
SCRIPTPATH="$(dirname "$SCRIPT")"
$SCRIPT
가 포함되어 .또, 「」에는 「」라고 하는 파일 경로가 기재되어 있습니다.$SCRIPTPATH
스크립트를 포함하는 디렉토리의 실제 경로.
이것을 사용하기 전에, 이 답변의 코멘트를 읽어 주세요.
읽기 쉬워요?다음은 대안입니다.심볼 링크를 무시합니다.
#!/bin/bash
currentDir=$(
cd $(dirname "$0")
pwd
)
echo -n "current "
pwd
echo script $currentDir
몇 년 전 위의 답변을 게시한 이후 저는 심볼링크를 적절하게 처리하는 Linux 고유의 패러다임을 사용하도록 제 방식을 발전시켰습니다.
ORIGIN=$(dirname $(readlink -f $0))
심플:
BASEDIR=$(readlink -f $0 | xargs dirname)
고급 연산자는 필요하지 않습니다.
다음 변수를 정의할 수 있습니다.
CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
또는 Bash에서 다음 함수를 사용할 수 있습니다.
realpath () {
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}
1번으로 하다에 이미 경로가 하고, 않은 경우 인수로 절대 경로를 합니다.$PWD
+ 인수 + filename '(') 없음)./
prefix)를 지정합니다.
관련:
이 질문에 대한 답변이 매우 늦었지만, 저는 다음과 같이 대답합니다.
SCRIPT=$( readlink -m $( type -p ${0} )) # Full path to script handling Symlinks
BASE_DIR=`dirname "${SCRIPT}"` # Directory script is run in
NAME=`basename "${SCRIPT}"` # Actual name of script even if linked
GitHub에 자사 제품 realpath-lib을 무료로 커뮤니티에서 사용할 수 있도록 배치했습니다.
뻔뻔한 플러그이지만 이 Bash 라이브러리를 사용하면 다음을 수행할 수 있습니다.
get_realpath <absolute|relative|symlink|local file>
이 기능은 라이브러리의 핵심입니다.
function get_realpath() {
if [[ -f "$1" ]]
then
# file *must* exist
if cd "$(echo "${1%/*}")" &>/dev/null
then
# file *may* not be local
# exception is ./file.ext
# try 'cd .; cd -;' *works!*
local tmppwd="$PWD"
cd - &>/dev/null
else
# file *must* be local
local tmppwd="$PWD"
fi
else
# file *cannot* exist
return 1 # failure
fi
# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success
}
Bash 4+를 사용하다, 이 기능에는, 「다보다」의 되어 있습니다.get_dirname
,get_filename
,get_stemname
및 validate_path validate_realpath
무료, 청결, 심플, 문서화가 잘 되어 있기 때문에, 학습 목적에도 사용할 수 있어 확실히 향상할 수 있습니다.여러 플랫폼에서 사용해 보십시오.
업데이트: 몇 가지 확인 및 테스트 후 위의 함수를 (dirname을 사용하지 않고 순수 Bash만 사용) 동일한 결과를 얻을 수 있는 것으로 대체하였습니다.
function get_realpath() {
[[ ! -f "$1" ]] && return 1 # failure : file does not exist.
[[ -n "$no_symlinks" ]] && local pwdp='pwd -P' || local pwdp='pwd' # do symlinks.
echo "$( cd "$( echo "${1%/*}" )" 2>/dev/null; $pwdp )"/"${1##*/}" # echo result.
return 0 # success
}
에는 환경 설정도 됩니다.no_symlinks
물리적 시스템에 대한 심볼 링크를 해결하는 기능을 제공합니다.기본적으로 심볼 링크는 그대로 유지됩니다.
이 문제를 다시 한 번 생각해 보겠습니다.이 스레드 내에서 참조되고 있는 매우 일반적인 솔루션은 다음과 같습니다.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
dirname을 사용하기 때문에 이 솔루션에는 관여하지 않았습니다.특히 보안상의 이유로 스크립트를 잠글 필요가 있는 경우 크로스 플랫폼의 문제가 발생할 수 있습니다.하지만 Bash만의 대안으로 다음을 사용하는 것은 어떨까요?
DIR="$( cd "$( echo "${BASH_SOURCE[0]%/*}" )" && pwd )"
이것이 선택사항이 될까요?
Bash 를 사용하는 경우는, 외부 커맨드에의 호출이 필요 없기 때문에, 이것이 가장 편리한 방법이라고 생각합니다.
THIS_PATH="${BASH_SOURCE[0]}";
THIS_DIR=$(dirname $THIS_PATH)
원라이너
`dirname $(realpath $0)`
승인된 솔루션에는 다음과 같은 불편함이 있습니다(저에게는 '소스 가능'하지 않습니다.source ../../yourScript
",$0
' 아, 아, 아, 아, 아, 아, 아, 아, 아, 맞다.'bash
함수3는경로를 는 ( = 3.0을 호출될 수 .source
경로 사용 ('절대 경로' 또는 ' 경로
('올바른 경로'란 다른 경로에서 직접 또는 "를 사용하여 호출된 경우에도 호출되는 스크립트의 완전한 절대 경로를 의미합니다).source
)"
#!/bin/bash
echo $0 executed
function bashscriptpath() {
local _sp=$1
local ascript="$0"
local asp="$(dirname $0)"
#echo "b1 asp '$asp', b1 ascript '$ascript'"
if [[ "$asp" == "." && "$ascript" != "bash" && "$ascript" != "./.bashrc" ]] ; then asp="${BASH_SOURCE[0]%/*}"
elif [[ "$asp" == "." && "$ascript" == "./.bashrc" ]] ; then asp=$(pwd)
else
if [[ "$ascript" == "bash" ]] ; then
ascript=${BASH_SOURCE[0]}
asp="$(dirname $ascript)"
fi
#echo "b2 asp '$asp', b2 ascript '$ascript'"
if [[ "${ascript#/}" != "$ascript" ]]; then asp=$asp ;
elif [[ "${ascript#../}" != "$ascript" ]]; then
asp=$(pwd)
while [[ "${ascript#../}" != "$ascript" ]]; do
asp=${asp%/*}
ascript=${ascript#../}
done
elif [[ "${ascript#*/}" != "$ascript" ]]; then
if [[ "$asp" == "." ]] ; then asp=$(pwd) ; else asp="$(pwd)/${asp}"; fi
fi
fi
eval $_sp="'$asp'"
}
bashscriptpath H
export H=${H}
은 '찾을 수 있다'을 발견하는 입니다.source
및 를합니다.${BASH_SOURCE[0]}
실제 대본을 돌려받을 수 있습니다.
Bourne 셸)sh
에 준거한 방법 「」를 참조해 주세요.
SCRIPT_HOME=`dirname $0 | while read a; do cd $a && pwd && break; done`
아마 다음 질문에 대한 답변이 도움이 될 것입니다.
Mac에서 GNU의 readlink -f 동작을 얻으려면 어떻게 해야 하나요?
에서 입니다.$PWD
★★★★★★★★★★★★★★★★★」$0
만 알고,$0
는, 「」을 하고, 「」을 「정규치환」으로 .abs_dir=${abs_dir//\/.\//\/}
아, 아, 아, 아, 아, 아, 아, 아, 아.
그래, 끔찍해 보인다는 건 알지만, 잘 될 거야. 완전 배쉬야.
이것을 시험해 보세요.
cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))
저는 한동안 (OS X에서는 사용하지 않지만) 다음 방법을 성공적으로 사용했는데, 이 방법은 쉘 내장만 사용하며 '소스 foobar'를 처리합니다.내가 본 바로는 sh' case.
아래 예시 코드의 한 가지 문제는 함수가 $PWD를 사용한다는 것입니다.$PWD는 함수 호출 시 정확할 수도 있고 그렇지 않을 수도 있습니다.그래서 그것은 처리되어야 한다.
#!/bin/bash
function canonical_path() {
# Handle relative vs absolute path
[ ${1:0:1} == '/' ] && x=$1 || x=$PWD/$1
# Change to dirname of x
cd ${x%/*}
# Combine new pwd with basename of x
echo $(pwd -P)/${x##*/}
cd $OLDPWD
}
echo $(canonical_path "${BASH_SOURCE[0]}")
type [
type cd
type echo
type pwd
그냥 재미삼아 순수하게 텍스트로만 작업을 수행하는 스크립트를 조금 해킹해 봤습니다.가장자리 케이스는 다 잡았으면 좋겠는데
에 주의:${var//pat/repl}
쪽 한 것은 한 수 없기 때문에 은 치환에 가 있습니다.그것은 교환에 문제가 있습니다./foo/../
를 들어, ★★★★★★★★★★★★★★★★★★★★·/*/../
그 전에 모든 걸 가져가게 될 거야, 단 하나의 엔트리가 아니라 말이야.그리고 이러한 패턴은 정규식이 아니기 때문에 어떻게 작동해야 하는지 모르겠습니다.여기 제가 생각해낸 멋진 솔루션이 있습니다.
그나저나, 처리되지 않은 가장자리 케이스가 있으면 알려주세요.
#!/bin/bash
canonicalize_path() {
local path="$1"
OIFS="$IFS"
IFS=$'/'
read -a parts < <(echo "$path")
IFS="$OIFS"
local i=${#parts[@]}
local j=0
local back=0
local -a rev_canon
while (($i > 0)); do
((i--))
case "${parts[$i]}" in
""|.) ;;
..) ((back++));;
*) if (($back > 0)); then
((back--))
else
rev_canon[j]="${parts[$i]}"
((j++))
fi;;
esac
done
while (($j > 0)); do
((j--))
echo -n "/${rev_canon[$j]}"
done
echo
}
canonicalize_path "/.././..////../foo/./bar//foo/bar/.././bar/../foo/bar/./../..//../foo///bar/"
또 다른 방법은 다음과 같습니다.
shopt -s extglob
selfpath=$0
selfdir=${selfpath%%+([!/])}
while [[ -L "$selfpath" ]];do
selfpath=$(readlink "$selfpath")
if [[ ! "$selfpath" =~ ^/ ]];then
selfpath=${selfdir}${selfpath}
fi
selfdir=${selfpath%%+([!/])}
done
echo $selfpath $selfdir
간단히 말하면, 다음과 같습니다.
MY_DIR=`dirname $0`
source $MY_DIR/_inc_db.sh
언급URL : https://stackoverflow.com/questions/4774054/reliable-way-for-a-bash-script-to-get-the-full-path-to-itself
'source' 카테고리의 다른 글
Ruby on Rails vs.의 경우 NET MVC 3.NET 가이? (0) | 2023.04.27 |
---|---|
WPF Textblock, Text Atribut의 줄 바꿈 (0) | 2023.04.22 |
Windows 명령줄에서 명령 실행 시간을 측정하려면 어떻게 해야 합니까? (0) | 2023.04.22 |
로컬 데이터베이스를 Windows Azure 데이터베이스로 복원하는 방법 (0) | 2023.04.22 |
색 그라데이션이 있는 UIView를 프로그래밍 방식으로 만듭니다. (0) | 2023.04.22 |