기본적으로 쉘 스크립트 파일 위치와 관련된 경로로 스크립트를 실행해야합니다. 현재 디렉토리를 스크립트 파일이있는 디렉토리와 동일한 디렉토리로 변경하려면 어떻게해야합니까?
기본적으로 쉘 스크립트 파일 위치와 관련된 경로로 스크립트를 실행해야합니다. 현재 디렉토리를 스크립트 파일이있는 디렉토리와 동일한 디렉토리로 변경하려면 어떻게해야합니까?
답변:
Bash에서는 다음과 같이 필요한 것을 얻습니다.
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
readlink
도 함께 사용해야 합니다 (아래 al의 답변 참조)
$BASH_SOURCE
대신에 사용하는 것이 더 안전합니다 . $0
$0
$BASH_SOURCE
Bash에 관한 것입니다. 질문은 일반적으로 쉘 스크립트에 관한 것입니다.
CUR_PATH=$(pwd)
또는 pwd
현재 디렉토리를 반환하십시오 (스크립트 부모 디렉토리 일 필요는 없습니다)!
$BASH_SOURCE
필요한 것을 반환합니다. 내 스크립트는 다른 스크립트에서 호출 및되고 $0
반환 .
하면서 $BASH_SOURCE
수익률 (내 경우에는 적절한 하위 디렉토리 scripts
).
원래 게시물에는 솔루션이 포함되어 있습니다 (응답을 무시하고 유용한 것은 추가하지 마십시오). 흥미로운 작업은 언급 된 unix 명령 readlink
과 옵션으로 수행됩니다 -f
. 스크립트가 상대 경로뿐만 아니라 절대 경로에 의해 호출 될 때 작동합니다.
bash의 경우 sh, ksh :
#!/bin/bash
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
tcsh의 경우 csh :
#!/bin/tcsh
# Absolute path to this script, e.g. /home/user/bin/foo.csh
set SCRIPT=`readlink -f "$0"`
# Absolute path this script is in, thus /home/user/bin
set SCRIPTPATH=`dirname "$SCRIPT"`
echo $SCRIPTPATH
참조 : https : //.com/a/246128/59087
readlink
. 그렇기 때문에 푸시 / 팝 (bash에 내장)을 사용하는 것이 좋습니다.
-f
OS X에서는 전혀 지원되지 않습니다 (사자로서). -f
예를 들어 pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
, 최대 한 수준의 간접적 해결을 통해 할 수있는 일을 포기 하거나 링크 된 게시물에 설명 된대로 자체 재귀 symlink-following 스크립트를 롤업 할 수 있습니다.
sh /some/other/directory/script.sh)
,이 경우 .
귀하의 비밀번호가 아닌 것/some/other/directory
답변에 대한 이전의 의견이 그것을 말했지만 다른 모든 답변 중에서 놓치기 쉽습니다.
bash를 사용할 때 :
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
dirname "$BASH_SOURCE"
대신 $ BASH_SOURCE에서 공백을 처리하는 데 사용해야 합니다.
"$(dirname "${BASH_SOURCE[0]}")"
bash를 사용한다고 가정합니다.
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
이 스크립트는 사용자가있는 디렉토리를 인쇄 한 다음 스크립트가있는 디렉토리를 인쇄해야합니다. 예를 들어 /
에서 스크립트 를 사용하여 호출 /home/mez/
하면 출력됩니다.
/
/home/mez
명령의 출력에서 변수를 할당 할 때,에서 명령을 포장 기억 $(
하고 )
또는 당신이 원하는 출력을받지 않습니다 -.
bash를 사용하는 경우 ....
#!/bin/bash
pushd $(dirname "${0}") > /dev/null
basedir=$(pwd -L)
# Use "pwd -P" for the path without links. man bash for more info.
popd > /dev/null
echo "${basedir}"
pushd
/를 popd
함께 cd $(dirname "${0}")
하고 cd -
그들이이있는 경우는, 다른 쉘에서 작동하도록 pwd -L
.
TheMarko가 제안한 바와 같이 :
BASEDIR=$(dirname $0)
echo $BASEDIR
스크립트가있는 동일한 디렉토리에서 스크립트를 실행하지 않으면 '.'값을 얻지 않는 한 작동합니다.
이 문제를 해결하려면 다음을 사용하십시오.
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = '.' ]
then
script_dir="$current_dir"
fi
이제 스크립트 전체에서 current_dir 변수를 사용하여 스크립트 디렉토리를 참조 할 수 있습니다. 그러나 여전히 symlink 문제가있을 수 있습니다.
이 질문에 대한 가장 좋은 대답은 여기에서 대답했습니다 :
Bash 스크립트의 소스 디렉토리 가져 오기
그리고 그건:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
스크립트는 어디에서 호출 되든지 스크립트의 전체 디렉토리 이름을 제공합니다.
작동 방식을 이해하려면 다음 스크립트를 실행할 수 있습니다.
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
TARGET="$(readlink "$SOURCE")"
if [[ $TARGET == /* ]]; then
echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
SOURCE="$TARGET"
else
DIR="$( dirname "$SOURCE" )"
echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"
POSIX oneliner로 만들어 봅시다 :
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
BSD 쉘을 포함한 많은 Bourne 호환 쉘에서 테스트되었습니다.
내가 아는 한, 나는 저자이며 공개 도메인에 넣었습니다. 자세한 내용은 https://www.jasan.tk/posts/2017-05-11-posix_shell_dirname_replacement/를 참조하십시오.
cd: too many arguments
경로에 공백이 있으면 작성된대로를 반환합니다 $PWD
. (명쾌한 수정이지만 실제로 얼마나 많은 사례가 있는지 보여줍니다)
소개
이 답변 은 The Thread에서 가장 깨졌지만 충격적으로 가장 많이 투표 된 답변을 수정 합니다 (TheMarko가 작성).
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
왜 "$ 0"이라는 dirname을 사용하면 작동하지 않습니까?
dirname $ 0 은 사용자가 매우 특정한 방식으로 스크립트를 시작한 경우에만 작동합니다. 이 답변이 실패하고 스크립트가 충돌하는 몇 가지 상황을 찾을 수있었습니다.
우선,이 답변이 어떻게 작동하는지 이해합시다. 그는 다음을 수행하여 스크립트 디렉토리를 얻습니다.
dirname "$0"
$ 0 은 스크립트를 호출하는 명령의 첫 부분을 나타냅니다 (기본적으로 인수없이 입력 된 명령입니다).
/some/path/./script argument1 argument2
$ 0 = "/ some / path /./ script"
dirname은 기본적으로 문자열에서 마지막 /를 찾아서 잘립니다. 따라서 할 경우 :
dirname /usr/bin/sha256sum
당신은 얻을 것이다 : / usr / bin
이 예제는 / usr / bin / sha256sum이 올바른 형식의 경로이지만
dirname "/some/path/./script"
잘 작동하지 않고 당신에게 줄 것입니다 :
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
스크립트와 같은 디렉토리에 있고이 명령으로 스크립트를 시작한다고 가정 해보십시오.
./script
이 상황에서 $ 0은 ./script이며 dirname $ 0은 다음을 제공합니다.
. #or BASEDIR=".", again this will crash your script
사용 :
sh script
전체 경로를 입력하지 않으면 BASEDIR = "도 제공됩니다."
상대 디렉토리 사용 :
../some/path/./script
다음과 같은 dirname $ 0를 제공합니다.
../some/path/.
/ some 디렉토리에 있고 이런 방식으로 스크립트를 호출하는 경우 (처음에는 /가없고 다시 상대 경로가 있음에 유의) :
path/./script.sh
dirname $ 0에 대해이 값을 얻습니다.
path/.
./path/./script (상대 경로의 다른 형식)는 다음을 제공합니다.
./path/.
basedir $ 0 이 작동 하는 유일한 두 가지 상황 은 사용자가 sh 또는 touch를 사용하여 스크립트를 시작하는 경우입니다.
$0=/some/path/script
dirname과 함께 사용할 수있는 경로를 제공합니다.
해결책
위에서 언급 한 상황을 모두 파악하고 감지하고 발생하는 경우 수정 사항을 적용하십시오.
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "\$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
너무 많은 답변, 모두 그럴듯하며 각각 각각 장단점 및 약간 다른 목표 (각각 언급해야 함). 다음은 모든 bash에서 모든 시스템에서 명확하고 작동하는 기본 목표를 충족시키는 다른 솔루션입니다 (bash 버전 readlink
또는 pwd
옵션 에 대한 가정은 없음 ). 흥미로운 문제이지만 일반적으로 실제로 원하는 것은 아닙니다), 경로의 공백 등과 같은 가장자리 사례를 처리하고 오류가 무시되고 문제가있는 경우 정상적인 기본값을 사용합니다.
각 구성 요소는 개별적으로 사용할 수있는 별도의 변수에 저장됩니다.
# script path, filename, directory
PROG_PATH=${BASH_SOURCE[0]} # this script's name
PROG_NAME=${PROG_PATH##*/} # basename of script (strip path)
PROG_DIR="$(cd "$(dirname "${PROG_PATH:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
blueyed의 답변에서 영감을 얻었습니다.
read < <(readlink -f $0 | xargs dirname)
cd $REPLY
그 트릭을해야합니다 :
echo `pwd`/`dirname $0`
호출 된 방식과 cwd에 따라보기 흉하게 보일 수 있지만 어디로 가야하는지 (또는 모양이 마음에 든다면 문자열을 조정할 수 있습니다).
`pwd`/`dirname $0`
하지만 여전히 심볼릭 링크에서 실패 할 수 있습니다