스크립트 자체 내에서 Bash 스크립트의 소스 디렉터리를 가져옵니다.

StackOverflow https://stackoverflow.com/questions/59895

  •  09-06-2019
  •  | 
  •  

문제

다음이 있는 디렉토리의 경로를 어떻게 얻나요? 세게 때리다 스크립트가 위치하고 있으며, 내부에 그 대본?

예를 들어, Bash 스크립트를 다른 애플리케이션의 실행 프로그램으로 사용하고 싶다고 가정해 보겠습니다.작업 디렉터리를 Bash 스크립트가 있는 디렉터리로 변경하여 다음과 같이 해당 디렉터리의 파일에 대해 작업을 수행할 수 있습니다.

$ ./application
도움이 되었습니까?

해결책

#!/bin/bash

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

어디에서 호출되든 스크립트의 전체 디렉토리 이름을 제공하는 유용한 한 줄짜리 도구입니다.

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

#!/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 이 코드 조각을 실행하기 전에 다른 디렉터리로 이동하면 결과가 올바르지 않을 수 있습니다!

또한 주의할 점은 $CDPATH 문제, 사용자가 cd를 현명하게 재정의하여 대신 출력을 stderr로 리디렉션한 경우 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는 스크립트가 있는 디렉토리가 아니라 현재 디렉토리가 무엇인지 알려주기 때문에 작업을 수행하지 않습니다.또한 스크립트에 대한 심볼릭 링크가 실행되면 실제 스크립트가 아닌 링크가 있는 위치에 대한 (아마도 상대) 경로를 얻게 됩니다.

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

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 발신자에서 수정되었습니다.
  • "./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 호출 방법에 관계없이 전체 경로로 제공됩니다.
스크립트 시작 부분에서 이것을 찾으십시오.

이 주석 및 코드 Copyleft는 GPL2.0 이상 또는 CC-SA 3.0(CreativeCommons Share Alike) 이상에 따라 선택 가능한 라이센스입니다.(다) 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/sh가 아닌 #!/bin/bash를 사용해야 합니다.

이렇게 해야 합니다:

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

경로의 심볼릭 링크 및 공백과 함께 작동합니다.다음에 대한 매뉴얼 페이지를 참조하십시오. 이름 그리고 읽기링크.

편집하다:

댓글 트랙을 보면 Mac OS에서는 작동하지 않는 것 같습니다.왜 그런지 모르겠습니다.어떤 제안이 있으십니까?

pwd 현재 작업 디렉토리를 찾는 데 사용할 수 있습니다. dirname 특정 파일의 디렉터리를 찾으려면(실행된 명령은 $0, 그래서 dirname $0 현재 스크립트의 디렉토리를 제공해야 합니다).

하지만, dirname 현재 작업 디렉토리와 관련이 있을 가능성이 높은 파일 이름의 디렉토리 부분을 정확하게 제공합니다.어떤 이유로 스크립트가 디렉터리를 변경해야 하는 경우 다음의 출력은 다음과 같습니다. dirname 무의미해집니다.

나는 다음을 제안합니다:

#!/bin/bash

reldir=`dirname $0`
cd $reldir
directory=`pwd`

echo "Directory is $directory"

이렇게 하면 상대 디렉토리가 아닌 절대 디렉토리를 얻게 됩니다.

스크립트는 별도의 bash 인스턴스에서 실행되므로 나중에 작업 디렉터리를 복원할 필요가 없습니다. 그러나 어떤 이유로든 스크립트에서 다시 변경하려는 경우 다음 값을 쉽게 할당할 수 있습니다. pwd 나중에 사용할 수 있도록 디렉터리를 변경하기 전에 변수에 저장하세요.

비록 단지

cd `dirname $0`

질문의 특정 시나리오를 해결하면 일반적으로 더 유용한 절대 경로가 있다는 것을 알았습니다.

나는 이것이 다른 사람들이 말한 것처럼 쉽지 않다고 생각합니다.pwd는 작동하지 않습니다. 현재 디렉토리가 반드시 스크립트가 있는 디렉토리일 필요는 없기 때문입니다.$0에도 항상 정보가 있는 것은 아닙니다.스크립트를 호출하는 다음 세 가지 방법을 고려하십시오.

./script

/usr/bin/script

script

첫 번째와 세 번째 방법에서 $0에는 전체 경로 정보가 없습니다.두 번째와 세 번째에서는 pwd가 작동하지 않습니다.세 번째 방법으로 dir을 얻는 유일한 방법은 경로를 실행하여 정확하게 일치하는 파일을 찾는 것입니다.기본적으로 코드는 OS가 수행하는 작업을 다시 실행해야 합니다.

요청한 작업을 수행하는 한 가지 방법은 /usr/share 디렉토리에 데이터를 하드코딩하고 전체 경로로 참조하는 것입니다.어쨌든 데이터는 /usr/bin 디렉토리에 있어서는 안 되므로 아마도 이렇게 해야 할 것입니다.

SCRIPT_DIR=$( cd ${0%/*} && pwd -P )

Mac OS X 10.6.6의 현재 작업 디렉토리를 가져옵니다.

DIR=$(cd "$(dirname "$0")"; pwd)
$(dirname "$(readlink -f "$BASH_SOURCE")")

나는 허용된 답변에 한 줄짜리 내용을 복사하여 붙여넣기 위해 이 페이지를 계속해서 방문하는 것에 지쳤습니다.문제는 이해하고 기억하는 것이 쉽지 않다는 것입니다.

다음은 기억하기 쉬운 스크립트입니다.

DIR=$(dirname "${BASH_SOURCE[0]}")  # get the directory name
DIR=$(realpath "${DIR}")    # resolve its full path if need be

이는 Linux에만 해당되지만 다음을 사용할 수 있습니다.

SELF=$(readlink /proc/$$/fd/255)

다음은 POSIX 호환 단일 라이너입니다.

SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"`

# test
echo $SCRIPT_PATH

나는 이들 중 하나를 모두 시도했지만 그들 중 누구도 효과가 없었습니다.하나는 매우 가까웠지만 심하게 부러지는 작은 버그가 있었습니다.그들은 경로를 따옴표로 묶는 것을 잊었습니다.

또한 많은 사람들은 쉘에서 스크립트를 실행한다고 가정하므로 새 스크립트를 열 때 기본값이 집에 있다는 사실을 잊어버리십시오.

크기를 확인하려면 다음 디렉터리를 사용해 보세요.

/var/아무도/생각하지 않았습니다/공백에 대해/디렉토리에 있음/이름/여기에 파일이 있습니다.text

이를 통해 실행 방법이나 위치에 관계없이 올바르게 작동합니다.

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename "$0"`"
echo "dirname: `dirname "$0"`"

따라서 이를 실제로 유용하게 만들기 위해 실행 중인 스크립트의 디렉터리로 변경하는 방법은 다음과 같습니다.

cd "`dirname "$0"`"

도움이 되었기를 바랍니다

간단하고 올바른 방법은 다음과 같습니다.

actual_path=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$actual_path")

설명:

  • ${BASH_SOURCE[0]} - 스크립트의 전체 경로입니다.이 값은 스크립트가 소스로 제공되는 경우에도 정확합니다. source <(echo 'echo $0') 인쇄물 세게 때리다, 이를 다음으로 대체하는 동안 ${BASH_SOURCE[0]} 스크립트의 전체 경로를 인쇄합니다.(물론 이는 Bash에 대한 종속성을 가져도 괜찮다고 가정합니다.)

  • readlink -f - 지정된 경로의 모든 심볼릭 링크를 재귀적으로 확인합니다.이것은 GNU 확장이며 (예를 들어) BSD 시스템에서는 사용할 수 없습니다.Mac을 실행하는 경우 Homebrew를 사용하여 GNU를 설치할 수 있습니다. coreutils 그리고 이것을 대체하다 greadlink -f.

  • 그리고 물론 dirname 경로의 상위 디렉터리를 가져옵니다.

나는 다음과 같은 것을 사용할 것입니다 :

# retrieve the full pathname of the called script
scriptPath=$(which $0)

# check whether the path is a link or not
if [ -L $scriptPath ]; then

    # it is a link then retrieve the target path and get the directory name
    sourceDir=$(dirname $(readlink -f $scriptPath))

else

    # otherwise just get the directory name of the script path
    sourceDir=$(dirname $scriptPath)

fi

e-satis 및 3bcdnlklvc04a가 지적한 솔루션에 대한 약간의 수정 그들의 대답

SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
    SCRIPT_DIR="$PWD"
    popd > /dev/null
}    

이는 나열된 모든 경우에 여전히 작동합니다.

편집하다:konsolebox 덕분에 pushd 실패 후 popd 방지

#!/bin/sh
PRG="$0"

# need this for relative symlinks
while [ -h "$PRG" ] ; do
   PRG=`readlink "$PRG"`
done

scriptdir=`dirname "$PRG"`

$_ $0의 대안으로 언급할 가치가 있습니다.Bash에서 스크립트를 실행하는 경우 허용되는 답변은 다음과 같이 단축될 수 있습니다.

DIR="$( dirname "$_" )"

이는 스크립트의 첫 번째 문이어야 합니다.

나는 주어진 많은 답변을 비교하고 좀 더 컴팩트한 솔루션을 생각해 냈습니다.이것들은 당신이 가장 좋아하는 조합에서 발생하는 모든 이상한 경우를 처리하는 것 같습니다:

  • 절대 경로 또는 상대 경로
  • 파일 및 디렉터리 소프트 링크
  • 다음으로 호출 script, bash script, bash -c script, source script, 또는 . script
  • 공백, 탭, 줄바꿈, 유니코드 등디렉토리 및/또는 파일 이름
  • 하이픈으로 시작하는 파일 이름

Linux에서 실행 중인 경우 다음을 사용하는 것 같습니다. proc 핸들은 현재 실행 중인 스크립트의 완전히 확인된 소스를 찾는 가장 좋은 솔루션입니다(대화형 세션에서 링크는 해당 /dev/pts/X):

resolved="$(readlink /proc/$$/fd/255 && echo X)" && resolved="${resolved%$'\nX'}"

약간의 추악함이 있지만 수정 사항은 간단하고 이해하기 쉽습니다.우리는 bash 기본 요소만 사용하는 것은 아니지만 그래도 괜찮습니다. readlink 작업을 상당히 단순화합니다.그만큼 echo X 추가하다 X 파일 이름의 후행 공백이 먹히지 않도록 변수 문자열의 끝에 매개변수 대체 ${VAR%X} 줄 끝에서 X.왜냐하면 readlink 자체적인 개행 문자를 추가합니다(이전 속임수가 아니었다면 일반적으로 명령 대체에서 먹혔을 것입니다). 그것도 제거해야 합니다.이는 다음을 사용하여 가장 쉽게 수행할 수 있습니다. $'' 다음과 같은 이스케이프 시퀀스를 사용할 수 있는 인용 체계 \n 줄 바꿈을 나타냅니다(이것은 또한 엉뚱한 이름의 디렉토리와 파일을 쉽게 만들 수 있는 방법이기도 합니다).

위 내용은 Linux에서 현재 실행 중인 스크립트를 찾는 데 필요한 사항을 다루지만, 해당 스크립트가 없는 경우 proc 파일 시스템을 마음대로 사용하거나 다른 파일의 완전히 확인된 경로를 찾으려는 경우 아래 코드가 도움이 될 수 있습니다.위의 단일 라이너에서 약간만 수정되었습니다.이상한 디렉토리/파일 이름을 갖고 놀고 있다면 두 가지 모두를 사용하여 출력을 확인하십시오. ls 그리고 readlink 다음과 같이 유익합니다. ls 대체하여 "단순화된" 경로를 출력합니다. ? 개행 같은 것들에 대해.

absolute_path=$(readlink -e -- "${BASH_SOURCE[0]}" && echo x) && absolute_path=${absolute_path%?x}
dir=$(dirname -- "$absolute_path" && echo x) && dir=${dir%?x}
file=$(basename -- "$absolute_path" && echo x) && file=${file%?x}

ls -l -- "$dir/$file"
printf '$absolute_path: "%s"\n' "$absolute_path"

다음을 사용해 보세요:

real=$(realpath $(dirname $0))

GNU coreutils readlink가 있는 시스템의 경우(예:리눅스):

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

사용할 필요가 없습니다 BASH_SOURCE 언제 $0 스크립트 파일 이름이 포함되어 있습니다.

그래서...나는 이것을 가지고 있다고 믿습니다.파티에 늦었지만 일부 사람들은 이 스레드를 접하게 되어 여기에 있다는 사실에 감사할 것이라고 생각합니다.댓글에 설명이 있어야 합니다.

#!/bin/sh # dash bash ksh # !zsh (issues). G. Nixon, 12/2013. Public domain.

## 'linkread' or 'fullpath' or (you choose) is a little tool to recursively
## dereference symbolic links (ala 'readlink') until the originating file
## is found. This is effectively the same function provided in stdlib.h as
## 'realpath' and on the command line in GNU 'readlink -f'.

## Neither of these tools, however, are particularly accessible on the many
## systems that do not have the GNU implementation of readlink, nor ship
## with a system compiler (not to mention the requisite knowledge of C).

## This script is written with portability and (to the extent possible, speed)
## in mind, hence the use of printf for echo and case statements where they
## can be substituded for test, though I've had to scale back a bit on that.

## It is (to the best of my knowledge) written in standard POSIX shell, and
## has been tested with bash-as-bin-sh, dash, and ksh93. zsh seems to have
## issues with it, though I'm not sure why; so probably best to avoid for now.

## Particularly useful (in fact, the reason I wrote this) is the fact that
## it can be used within a shell script to find the path of the script itself.
## (I am sure the shell knows this already; but most likely for the sake of
## security it is not made readily available. The implementation of "$0"
## specificies that the $0 must be the location of **last** symbolic link in
## a chain, or wherever it resides in the path.) This can be used for some
## ...interesting things, like self-duplicating and self-modifiying scripts.

## Currently supported are three errors: whether the file specified exists
## (ala ENOENT), whether its target exists/is accessible; and the special
## case of when a sybolic link references itself "foo -> foo": a common error
## for beginners, since 'ln' does not produce an error if the order of link
## and target are reversed on the command line. (See POSIX signal ELOOP.)

## It would probably be rather simple to write to use this as a basis for
## a pure shell implementation of the 'symlinks' util included with Linux.

## As an aside, the amount of code below **completely** belies the amount
## effort it took to get this right -- but I guess that's coding for you.

##===-------------------------------------------------------------------===##

for argv; do :; done # Last parameter on command line, for options parsing.

## Error messages. Use functions so that we can sub in when the error occurs.

recurses(){ printf "Self-referential:\n\t$argv ->\n\t$argv\n" ;}
dangling(){ printf "Broken symlink:\n\t$argv ->\n\t"$(readlink "$argv")"\n" ;}
errnoent(){ printf "No such file: "$@"\n" ;} # Borrow a horrible signal name.

# Probably best not to install as 'pathfull', if you can avoid it.

pathfull(){ cd "$(dirname "$@")"; link="$(readlink "$(basename "$@")")"

## 'test and 'ls' report different status for bad symlinks, so we use this.

 if [ ! -e "$@" ]; then if $(ls -d "$@" 2>/dev/null) 2>/dev/null;  then
    errnoent 1>&2; exit 1; elif [ ! -e "$@" -a "$link" = "$@" ];   then
    recurses 1>&2; exit 1; elif [ ! -e "$@" ] && [ ! -z "$link" ]; then
    dangling 1>&2; exit 1; fi
 fi

## Not a link, but there might be one in the path, so 'cd' and 'pwd'.

 if [ -z "$link" ]; then if [ "$(dirname "$@" | cut -c1)" = '/' ]; then
   printf "$@\n"; exit 0; else printf "$(pwd)/$(basename "$@")\n"; fi; exit 0
 fi

## Walk the symlinks back to the origin. Calls itself recursivly as needed.

 while [ "$link" ]; do
   cd "$(dirname "$link")"; newlink="$(readlink "$(basename "$link")")"
   case "$newlink" in
    "$link") dangling 1>&2 && exit 1                                       ;;
         '') printf "$(pwd)/$(basename "$link")\n"; exit 0                 ;;
          *) link="$newlink" && pathfull "$link"                           ;;
   esac
 done
 printf "$(pwd)/$(basename "$newlink")\n"
}

## Demo. Install somewhere deep in the filesystem, then symlink somewhere 
## else, symlink again (maybe with a different name) elsewhere, and link
## back into the directory you started in (or something.) The absolute path
## of the script will always be reported in the usage, along with "$0".

if [ -z "$argv" ]; then scriptname="$(pathfull "$0")"

# Yay ANSI l33t codes! Fancy.
 printf "\n\033[3mfrom/as: \033[4m$0\033[0m\n\n\033[1mUSAGE:\033[0m   "
 printf "\033[4m$scriptname\033[24m [ link | file | dir ]\n\n         "
 printf "Recursive readlink for the authoritative file, symlink after "
 printf "symlink.\n\n\n         \033[4m$scriptname\033[24m\n\n        "
 printf " From within an invocation of a script, locate the script's "
 printf "own file\n         (no matter where it has been linked or "
 printf "from where it is being called).\n\n"

else pathfull "$@"
fi

다음 교차 호환 솔루션을 사용해 보십시오.

CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"

~처럼 realpath 또는 readlink 명령을 항상 사용할 수 있는 것은 아닙니다(운영 체제에 따라 다름). ${BASH_SOURCE[0]} bash 쉘에서만 사용할 수 있습니다.

또는 bash에서 다음 기능을 사용해 볼 수 있습니다.

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

이 함수는 1개의 인수를 사용합니다.인수에 이미 절대 경로가 있으면 그대로 인쇄하고, 그렇지 않으면 인쇄합니다. $PWD 변수 + 파일 이름 인수(없음 ./ 접두사).

관련된:

흠, Path에서 Basename & Dirname이 그것을 자르지 않고 길을 걷는 것이 어렵다면 (부모가 경로를 내보내지 않으면?).그러나 쉘은 스크립트에 열린 핸들이 있어야하며, 핸들은 #255입니다.

SELF=`readlink /proc/$$/fd/255`

나를 위해 일합니다.

많은 답변을 요약하면 다음과 같습니다.

    Script: "/tmp/src dir/test.sh"
    Calling folder: "/tmp/src dir/other"

사용된 명령

    echo Script-Dir : `dirname "$(realpath $0)"`
    echo Script-Dir : $( cd ${0%/*} && pwd -P )
    echo Script-Dir : $(dirname "$(readlink -f "$0")")
    echo
    echo Script-Name : `basename "$(realpath $0)"`
    echo Script-Name : `basename $0`
    echo
    echo Script-Dir-Relative : `dirname "$BASH_SOURCE"`
    echo Script-Dir-Relative : `dirname $0`
    echo
    echo Calling-Dir : `pwd`

출력:

     Script-Dir : /tmp/src dir
     Script-Dir : /tmp/src dir
     Script-Dir : /tmp/src dir

     Script-Name : test.sh
     Script-Name : test.sh

     Script-Dir-Relative : ..
     Script-Dir-Relative : ..

     Calling-Dir : /tmp/src dir/other

보다https://pastebin.com/J8KjxrPF

이것은 bash-3.2에서 작동합니다.

path="$( dirname "$( which "$0" )" )"

사용법의 예는 다음과 같습니다.

당신이 가지고 있다고 말해보세요 ~/빈 디렉토리는 귀하의 $PATH.스크립트가 있습니다 이 디렉토리 안에.그것 원천스크립트 ~/빈/lib/B.포함된 스크립트가 원래 스크립트와 관련된 위치(하위 디렉터리)를 알고 있습니다. lib), 그러나 사용자의 현재 디렉터리와 관련된 위치는 아닙니다.

이는 다음과 같이 해결됩니다(내부 ):

source "$( dirname "$( which "$0" )" )/lib/B"

사용자가 어디에 있는지, 스크립트를 어떻게 호출하는지는 중요하지 않으며 이는 항상 작동합니다.

이들 중 어느 것도 OS X의 Finder가 시작한 bash 스크립트에서 작동하지 않았습니다. 결국 다음을 사용했습니다.

SCRIPT_LOC="`ps -p $$ | sed /PID/d | sed s:.*/Network/:/Network/: |
sed s:.*/Volumes/:/Volumes/:`"

예쁘지는 않지만 작업이 완료됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top