[bash] 스크립트 자체에서 Bash 스크립트의 소스 디렉토리를 얻는 방법

해당 스크립트 에서 Bash 스크립트가 있는 디렉토리의 경로를 얻으려면 어떻게합니까 ?

Bash 스크립트를 다른 응용 프로그램의 실행기로 사용하고 싶습니다. 작업 디렉토리를 Bash 스크립트가있는 디렉토리로 변경하고 싶으므로 해당 디렉토리의 파일을 다음과 같이 조작 할 수 있습니다.

$ ./application



답변

#!/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

어디에서 스크립트를 호출하든 스크립트의 전체 디렉토리 이름을 제공하는 유용한 one-liner입니다.

스크립트를 찾는 데 사용 된 경로의 마지막 구성 요소가 심볼릭 링크가 아닌 한 (디렉토리 링크는 정상 임) 작동합니다. 스크립트 자체에 대한 링크도 해결하려면 여러 줄 솔루션이 필요합니다.

#!/bin/bash

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"

이 마지막 하나는 별명의 조합으로 작동 source, bash -c심볼릭 링크 등

주의 : 당신이 경우에 cd이 코드를 실행하기 전에 다른 디렉토리로, 결과가 잘못 될 수 있습니다!

또한 사용자가 cd를 현명하게 재정 의하여 출력을 stderr로 리디렉션하는 경우 ( Mac에서 호출 할 때와 같은 이스케이프 시퀀스 포함) $CDPATHgotchas 및 stderr 출력 부작용 update_terminal_cwd >&2에주의하십시오. 명령 >/dev/null 2>&1끝에 추가하면 cd두 가지 가능성이 모두 해결됩니다.

작동 방식을 이해하려면 다음과 같은 더 자세한 양식을 실행하십시오.

#!/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" )" >/dev/null 2>&1 && pwd )"
if [ "$DIR" != "$RDIR" ]; then
  echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"

그리고 다음과 같이 인쇄됩니다.

SOURCE './scriptdir.sh' is a relative symlink to 'sym2/scriptdir.sh' (relative to '.')
SOURCE is './sym2/scriptdir.sh'
DIR './sym2' resolves to '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
DIR is '/home/ubuntu/dotfiles/fo fo/real/real1/real2'


답변

사용 dirname "$0":

#!/bin/bash
echo "The script you are running has basename `basename "$0"`, dirname `dirname "$0"`"
echo "The present working directory is `pwd`"

사용 pwd당신이이에 포함 된 디렉토리에서 스크립트를 실행하지 않으면 작동하지 않습니다 만.

[matt@server1 ~]$ pwd
/home/matt
[matt@server1 ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[matt@server1 ~]$ cd /tmp
[matt@server1 tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp


답변

dirname명령은 가장 기본적이며 단순히 $0(스크립트 이름) 변수 에서 파일 이름까지의 경로를 구문 분석합니다 .

dirname "$0"

그러나 매트 b가 지적했듯이 반환되는 경로는 스크립트 호출 방법에 따라 다릅니다. pwd스크립트가있는 디렉토리가 아니라 현재 디렉토리 만 알려주기 때문에 작업을 수행하지 않습니다. 또한 스크립트에 대한 심볼릭 링크가 실행되면 (아마도 상대적인) 경로를 얻게됩니다 실제 스크립트가 아닌 링크가있는 위치

다른 사람들은 readlink명령 을 언급 했지만 가장 간단하게 다음을 사용할 수 있습니다.

dirname "$(readlink -f "$0")"

readlink스크립트 경로를 파일 시스템의 루트에서 절대 경로로 해석합니다. 따라서 단일 또는 이중 도트, 물결표 및 / 또는 기호 링크가 포함 된 경로는 전체 경로로 해석됩니다.

다음은 이들 각각을 보여주는 스크립트입니다 whatdir.sh.

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename $0`"
echo "dirname: `dirname $0`"
echo "dirname/readlink: $(dirname $(readlink -f $0))"

상대 경로를 사용하여 내 홈 디렉토리 에서이 스크립트를 실행하십시오.

>>>$ ./whatdir.sh
pwd: /Users/phatblat
$0: ./whatdir.sh
basename: whatdir.sh
dirname: .
dirname/readlink: /Users/phatblat

다시 말하지만 스크립트의 전체 경로를 사용하십시오.

>>>$ /Users/phatblat/whatdir.sh
pwd: /Users/phatblat
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

이제 디렉토리 변경 :

>>>$ cd /tmp
>>>$ ~/whatdir.sh
pwd: /tmp
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

마지막으로 심볼릭 링크를 사용하여 스크립트를 실행하십시오.

>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh
pwd: /tmp
$0: ./whatdirlink.sh
basename: whatdirlink.sh
dirname: .
dirname/readlink: /Users/phatblat


답변

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}"
if ([ -h "${SCRIPT_PATH}" ]); then
  while([ -h "${SCRIPT_PATH}" ]); do cd `dirname "$SCRIPT_PATH"`;
  SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

다음을 포함한 모든 버전에서 작동

  • 다중 깊이 소프트 링크를 통해 호출 될 때
  • 때 파일
  • 스크립트 ” source“일명 .(점) 연산자로 스크립트를 호출 한 경우
  • $0호출자가 arg 를 수정 한 경우
  • "./script"
  • "/full/path/to/script"
  • "/some/path/../../another/path/script"
  • "./some/folder/script"

또는, bash는 스크립트 자체가 경우 상대 심볼릭 링크 당신이 원하는 의 전체 경로를 그것을 따라 반환이 연결된에 스크립트 :

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
if ([ -h "${SCRIPT_PATH}" ]) then
  while([ -h "${SCRIPT_PATH}" ]) do cd `dirname "$SCRIPT_PATH"`; SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

SCRIPT_PATH어떻게 호출 되든 전체 경로로 제공됩니다.
스크립트 시작시이 위치를 찾으십시오.

이 설명과 코드는 GPL2.0 이상 또는 CC-SA 3.0 (CreativeCommons Share Alike) 이상에서 선택 가능한 라이센스 인 Copyleft입니다. (c) 2008. 모든 권리 보유. 어떤 종류의 보증도하지 않습니다. 경고를 받았습니다.
http://www.gnu.org/licenses/gpl-2.0.txt
http://creativecommons.org/licenses/by-sa/3.0/
18eedfe1c99df68dc94d4a94712a71aaa8e1e9e36cacf421b9463dd2bbaa02906d0d6656


답변

짧은 답변:

`dirname $0`

또는 ( 바람직하게는 ) :

$(dirname "$0")


답변

당신은 사용할 수 있습니다 $BASH_SOURCE:

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

Bash 확장이므로 사용 #!/bin/bash하지 않아야 #!/bin/sh합니다.


답변

이것은해야합니다 :

DIR="$(dirname "$(readlink -f "$0")")"

이것은 경로의 심볼릭 링크 및 공백과 함께 작동합니다.

dirname및에 대한 매뉴얼 페이지를 참조하십시오 readlink.

댓글 트랙에서 Mac OS에서는 작동하지 않는 것 같습니다. 왜 그런지 모르겠습니다. 어떤 제안?