programing

스크립트 자체 내에서 Bash 스크립트가 있는 디렉토리를 가져오려면 어떻게 해야 합니까?

topblog 2023. 4. 28. 19:59
반응형

스크립트 자체 내에서 Bash 스크립트가 있는 디렉토리를 가져오려면 어떻게 해야 합니까?

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

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

$ ./application
#!/usr/bin/env bash

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

는 스크립트가 어디에서 호출되는지에 관계없이 스크립트의 전체 디렉터리 이름을 제공하는 유용한 단일 행입니다.

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

#!/usr/bin/env bash

SOURCE=${BASH_SOURCE[0]}
while [ -L "$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로 리디렉션한 경우 gotchas 및 stderr 출력 부작용을 주의하십시오(예: 호출 시 이스케이프 시퀀스 포함).update_terminal_cwd >&2Mac(으)로 표시),>/dev/null 2>&1의▁▁of▁.cd지휘부가 두 가지 가능성을 모두 처리할 것입니다.

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

#!/usr/bin/env bash

SOURCE=${BASH_SOURCE[0]}
while [ -L "$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":

#!/usr/bin/env 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

명령은 가장 기본적이며, 단순히 파일 이름까지 경로를 구문 분석합니다.$0 이름) (으)로 표시됨:

dirname -- "$0";

그러나 mattb가 지적했듯이 스크립트를 어떻게 부르느냐에 따라 반환되는 경로가 다릅니다. pwd스크립트가 어떤 디렉터리에 있는지가 아니라 현재 디렉터리만 알려주기 때문에 이 작업을 수행하지 않습니다.또한 스크립트에 대한 심볼릭 링크가 실행되면 실제 스크립트가 아닌 링크가 있는 위치에 대한 (아마 상대적인) 경로를 얻을 수 있습니다.

다른 사람들은 다음을 언급했습니다.readlink명령을 사용할 수 있지만 가장 단순한 방법은 다음과 같습니다.

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

readlink스크립트 경로를 파일 시스템 루트의 절대 경로로 확인합니다.따라서 단일 또는 이중 점, 타일 및/또는 심볼 링크를 포함하는 모든 경로는 전체 경로로 확인됩니다.

여기 이것들을 각각 보여주는 대본이 있습니다.whatdir.sh:

#!/usr/bin/env 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

그러나 스크립트가 bash에서 실행되는 대신 소스가 되는 경우 이 작업이 작동하지 않는 경우가 있습니다.

>>>$ cd /tmp
>>>$ . ~/whatdir.sh  
pwd: /tmp
$0: bash
basename: bash
dirname: .
dirname/readlink: /tmp
pushd . > '/dev/null';
SCRIPT_PATH="${BASH_SOURCE[0]:-$0}";

while [ -h "$SCRIPT_PATH" ];
do
    cd "$( dirname -- "$SCRIPT_PATH"; )";
    SCRIPT_PATH="$( readlink -f -- "$SCRIPT_PATH"; )";
done

cd "$( dirname -- "$SCRIPT_PATH"; )" > '/dev/null';
SCRIPT_PATH="$( pwd; )";
popd  > '/dev/null';

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

  • 다중 깊이 소프트 링크를 통해 호출될 때,
  • 서류철을 작성할 때.
  • 령에의해스호가출때될트립명크▁called"로 될 때source 명일.(점) 연산자
  • arg arg 때 는할.$0호출자에서 수정되었습니다.
  • "./script"
  • "/full/path/to/script"
  • "/some/path/../../another/path/script"
  • "./some/folder/script"

또는 Bash 스크립트 자체가 상대적 심볼 링크인 경우 이를 따르고 링크 대상 스크립트의 전체 경로를 반환합니다.

pushd . > '/dev/null';
SCRIPT_PATH="${BASH_SOURCE[0]:-$0}";

while [ -h "$SCRIPT_PATH" ];
do
    cd "$( dirname -- "$SCRIPT_PATH"; )";
    SCRIPT_PATH="$( readlink -f -- "$SCRIPT_PATH"; )";
done

cd "$( dirname -- "$SCRIPT_PATH"; )" > '/dev/null';
SCRIPT_PATH="$( pwd; )";
popd  > '/dev/null';

SCRIPT_PATH어떤 식으로 부르든 전체 경로로 주어집니다.

스크립트를 시작할 때 이것을 찾으십시오.

사용할 수 있습니다.$BASH_SOURCE:

#!/usr/bin/env bash

scriptdir="$( dirname -- "$BASH_SOURCE"; )";

사용해야 한다는 점에 유의하십시오.#!/bin/bash그리고 아닌#!/bin/shBash 확장자이기 때문에.

기억하기 쉬운 스크립트는 다음과 같습니다.

DIR="$( dirname -- "${BASH_SOURCE[0]}"; )";   # Get the directory name
DIR="$( realpath -e -- "$DIR"; )";    # Resolve its full path if need be

단답:

"`dirname -- "$0";`"

또는 (바람직하게):

"$( dirname -- "$0"; )"

이렇게 하면 됩니다.

DIR="$(dirname "$(realpath "$0")")"

경로의 심볼릭 링크 및 공백에서 작동합니다.

』 『 』 『 』 『 』 『 』 『 』 『 』 『 』 『 『 』 『 』 『 』 『 』 『 』 『 』 『 』 『 』 『 』 『dirname그리고.realpath.

MacOS 지원 방법에 대한 의견을 추가해 주십시오.확인할 수 있어서 죄송합니다.

pwd현재 작업 디렉터리를 찾는 데 사용할 수 있습니다.dirname 파일의 디렉터리를 .$0,그렇게dirname $0현재 스크립트의 디렉터리를 제공해야 합니다.

하만지,dirname파일 이름의 디렉터리 부분을 정확하게 제공합니다. 이 부분은 현재 작업 디렉터리에 상대적일 가능성이 높습니다.에는 " " " " 에서 됩니다.dirname의미가 없어집니다.

다음을 제안합니다.

#!/usr/bin/env bash

reldir="$( dirname -- "$0"; )";
cd "$reldir";
directory="$( pwd; )";

echo "Directory is ${directory}";

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

어떤 "Bash"라는 할 수 .pwd나중에 사용할 수 있도록 디렉터리를 변경하기 전에 변수에 추가합니다.

비록 단지

cd "$( dirname -- "$0"; )";

문제의 구체적인 시나리오를 해결합니다. 일반적으로 더 유용하게 사용할 수 있는 절대적인 경로가 있습니다.

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

Mac OS X v10.6.6(Snow Leopard)의 현재 작업 디렉토리를 가져옵니다.

DIR=$(cd "$(dirname "$0")"; pwd)

저는 이것이 다른 사람들이 생각했던 것처럼 쉽지 않다고 생각합니다. pwd현재 디렉터리가 스크립트가 있는 디렉터리일 필요는 없으므로 작동하지 않습니다. $0항상 정보를 가지고 있는 것도 아닙니다.스크립트를 호출하는 세 가지 방법을 고려합니다.

./script

/usr/bin/script

script

와 세 방법으로 첫째와세방법로으째번번▁in로방▁the으법▁third.$0전체 경로 정보가 없습니다.세 번째에는 두번와세번는에째째▁in는번.pwd작동하지 않습니다.세 번째 방법으로 디렉터리를 가져오는 유일한 방법은 경로를 실행하여 일치하는 파일을 찾는 것입니다.기본적으로 코드는 OS가 하는 것을 다시 실행해야 합니다.

당신이 요청하는 것을 하는 한 가지 방법은 단지 데이터를 하드 코딩하는 것입니다./usr/share전체 경로를 기준으로 디렉터리를 참조합니다.데이터가 다음 위치에 있으면 안 됩니다./usr/bin어쨌든 디렉토리, 그래서 이것은 아마도 해야 할 일일 것입니다.

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

이는 Linux 전용이지만 다음을 사용할 수 있습니다.

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

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

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

# test
echo $SCRIPT_PATH

가장 짧고 우아한 방법은 다음과 같습니다.

#!/bin/bash
DIRECTORY=$(cd `dirname $0` && pwd)
echo $DIRECTORY

이것은 모든 플랫폼에서 작동하며 매우 깨끗합니다.

자세한 내용은 "어떤 디렉터리에 bash 스크립트가 있습니까?"에서 확인할 수 있습니다.

요약:.

FULL_PATH_TO_SCRIPT="$(realpath "${BASH_SOURCE[-1]}")"

# OR, if you do NOT need it to work for **sourced** scripts too:
# FULL_PATH_TO_SCRIPT="$(realpath "$0")"

# OR, depending on which path you want, in case of nested `source` calls
# FULL_PATH_TO_SCRIPT="$(realpath "${BASH_SOURCE[0]}")"

# OR, add `-s` to NOT expand symlinks in the path:
# FULL_PATH_TO_SCRIPT="$(realpath -s "${BASH_SOURCE[-1]}")"

SCRIPT_DIRECTORY="$(dirname "$FULL_PATH_TO_SCRIPT")"
SCRIPT_FILENAME="$(basename "$FULL_PATH_TO_SCRIPT")"

세부사항:

실행 인 스크립트의 전체 파일 경로, 전체 디렉터리 및 기본 파일 이름을 가져오는 방법...

...다른 bash 함수 또는 스크립트 내에서 호출된 스크립트를 호출하거나 중첩된 소싱을 사용하는 경우에도!

대부분의 경우 방금 호출한 스크립트의 전체 경로만 가져오면 됩니다.이 작업은 다음을 사용하여 쉽게 수행할 수 있습니다.realpath:realpath는 GNU 코어유틸리티의 일부입니다.아직 설치되지 않은 경우(Ubuntu에서는 기본값으로 제공됨) 다음을 사용하여 설치할 수 있습니다.sudo apt update && sudo apt install coreutils.

get_script_path.sh(이 스크립트의 최신 버전은 내 eRCaGuy_hello_world repo의 get_script_path.sh를 참조하십시오):

#!/bin/bash

# A. Obtain the full path, and expand (walk down) symbolic links
# A.1. `"$0"` works only if the file is **run**, but NOT if it is **sourced**.
# FULL_PATH_TO_SCRIPT="$(realpath "$0")"
# A.2. `"${BASH_SOURCE[-1]}"` works whether the file is sourced OR run, and even
# if the script is called from within another bash function!
# NB: if `"${BASH_SOURCE[-1]}"` doesn't give you quite what you want, use
# `"${BASH_SOURCE[0]}"` instead in order to get the first element from the array.
FULL_PATH_TO_SCRIPT="$(realpath "${BASH_SOURCE[-1]}")"
# B.1. `"$0"` works only if the file is **run**, but NOT if it is **sourced**.
# FULL_PATH_TO_SCRIPT_KEEP_SYMLINKS="$(realpath -s "$0")"
# B.2. `"${BASH_SOURCE[-1]}"` works whether the file is sourced OR run, and even
# if the script is called from within another bash function!
# NB: if `"${BASH_SOURCE[-1]}"` doesn't give you quite what you want, use
# `"${BASH_SOURCE[0]}"` instead in order to get the first element from the array.
FULL_PATH_TO_SCRIPT_KEEP_SYMLINKS="$(realpath -s "${BASH_SOURCE[-1]}")"

# You can then also get the full path to the directory, and the base
# filename, like this:
SCRIPT_DIRECTORY="$(dirname "$FULL_PATH_TO_SCRIPT")"
SCRIPT_FILENAME="$(basename "$FULL_PATH_TO_SCRIPT")"

# Now print it all out
echo "FULL_PATH_TO_SCRIPT = \"$FULL_PATH_TO_SCRIPT\""
echo "SCRIPT_DIRECTORY    = \"$SCRIPT_DIRECTORY\""
echo "SCRIPT_FILENAME     = \"$SCRIPT_FILENAME\""

중첩 통화에 대한 중요 참고: 만약"${BASH_SOURCE[-1]}"위는 당신이 원하는 것을 주지 않습니다. 사용해 보십시오."${BASH_SOURCE[0]}"첫대.째번신(번)0의 첫 항목을 합니다.-1인덱스는 배열의 마지막 항목을 제공합니다.원하는 항목에 따라 첫 번째 항목을 실제로 원할 수도 있습니다.저는 이것이 사실이라는 것을 제가 정보를 했을 때 발견했습니다.~/.bashrc와 함께. ~/.bashrc출처가 어디입니까?~/.bash_aliases와 함께. ~/.bash_aliases그리고 나는 그것을 원했습니다.realpath( 기호 링크에 (으)로 이동합니다~/.bash_aliases파일, 에 대한 것이 아님~/.bashrc파일. 이것들이 중첩되어 있기 때문에. source 호출, 용사 사용"${BASH_SOURCE[0]}": 내가원는주길: ▁to로의 된 길.~/.bash_aliases 사용"${BASH_SOURCE[-1]}"하지만, 내가 원하지 않는 것을 주었습니다: 확장된 길.~/.bashrc.

명령 및 출력 예제:

  1. 스크립트 실행:
    ~/GS/dev/eRCaGuy_hello_world/bash$ ./get_script_path.sh 
    FULL_PATH_TO_SCRIPT = "/home/gabriel/GS/dev/eRCaGuy_hello_world/bash/get_script_path.sh"
    SCRIPT_DIRECTORY    = "/home/gabriel/GS/dev/eRCaGuy_hello_world/bash"
    SCRIPT_FILENAME     = "get_script_path.sh"
    
  2. 스크립트를 사용하여 소스 지정. get_script_path.sh또는source get_script_path.sh가 (사용기때결위완동와일전다합니히는과문에했▁(사다▁is▁i▁(▁result▁because니동합일▁▁the▁asthe"${BASH_SOURCE[-1]}"에 대신 에."$0"):
    ~/GS/dev/eRCaGuy_hello_world/bash$ . get_script_path.sh 
    FULL_PATH_TO_SCRIPT = "/home/gabriel/GS/dev/eRCaGuy_hello_world/bash/get_script_path.sh"
    SCRIPT_DIRECTORY    = "/home/gabriel/GS/dev/eRCaGuy_hello_world/bash"
    SCRIPT_FILENAME     = "get_script_path.sh"
    

사용하는 경우"$0"에 대신 에."${BASH_SOURCE[-1]}"스크립트를 실행할 는 위와 동일한 출력이 나오지만 스크립트를 소스할 때는 이 원하지 않는 출력이 대신 나옵니다.

~/GS/dev/eRCaGuy_hello_world/bash$ . get_script_path.sh 
FULL_PATH_TO_SCRIPT               = "/bin/bash"
SCRIPT_DIRECTORY                  = "/bin"
SCRIPT_FILENAME                   = "bash"

그고리를 하면 분히당사다면한용이신명면▁and다사▁if한ly,▁you."$BASH_SOURCE""${BASH_SOURCE[-1]}"스크립트가 다른 bash 함수 내에서 호출되면 작동하지 않습니다.그래서, 사용."${BASH_SOURCE[-1]}"따라서 이 두 가지 문제를 모두 해결하기 때문에 가장 좋은 방법입니다!아래 참조를 참조하십시오.

사의차이의 realpath그리고.realpath -s:

:realpath또한 심볼릭 링크를 사용하여 심볼릭 링크를 가리키지 않고 대상을 결정하고 가리킵니다.이 이 행동을 ( 나는 않습니다), 하세요.-s에▁realpath위의 명령을 사용하여 행을 대신 다음과 같이 표시합니다.

# Obtain the full path, but do NOT expand (walk down) symbolic links; in
# other words: **keep** the symlinks as part of the path!
FULL_PATH_TO_SCRIPT="$(realpath -s "${BASH_SOURCE[-1]}")"

이렇게 하면 심볼릭 링크가 확장되지 않습니다.오히려, 그들은 전체 경로의 심볼릭 링크로서 그대로 남아 있습니다.

위의 코드는 이제 bash/get_script_path.sh 파일에 있는 나의 eRCaGuy_hello_world repo의 일부입니다.이 파일을 참조하고 실행하여 전체 예제 사용 및 사용경로에 OUT 기호가 있습니다.두 경우 모두 파일 하단의 출력 예를 참조하십시오.

참조:

  1. 주어진 상대 경로를 절대 경로로 검색하는 방법
  2. 나에게 그것에 대해 가르쳐 주었습니다.BASH_SOURCE변수:Unix & Linux: 소스 셸 스크립트의 경로 결정
  3. 나에게 가르쳐 준 것은BASH_SOURCE실제로 어레이이며, 우리는 그것의 마지막 요소가 함수 내에서 예상대로 작동하기를 원합니다(그래서 제가 사용한 이유)."${BASH_SOURCE[-1]}"여기 내 코드로):Unix & Linux: 소스 셸 스크립트의 경로 결정
  4. man bash --> 색BASH_SOURCE:

    BASH_SOURCE

    로, 해당 셸이 멤가소변로, 입니다.FUNCNAME배열 변수가 정의되었습니다. 함수 셸 수${FUNCNAME[$i]}에 정의되어 있습니다.${BASH_SOURCE[$i]}에서 전화가 왔습니다.${BASH_SOURCE[$i+1]}.

참고 항목:

  1. [myanswer] Unix & Linux: 소스 셸 스크립트의 경로 결정
#!/bin/sh
PRG="$0"

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

scriptdir=`dirname "$PRG"`

간단하고 정확한 방법은 다음과 같습니다.

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

설명:

  • ${BASH_SOURCE[0]} 스크립트의 전체 경로입니다.이 값은 스크립트가 소스될 때에도 정확합니다.source <(echo 'echo $0')Bash를 인쇄하는 동시에${BASH_SOURCE[0]}스크립트의 전체 경로를 인쇄합니다. (물론, 이것은 Bash에 의존하는 것이 괜찮다고 가정합니다.)

  • readlink -f 지정한 경로의 심볼 링크를 재귀적으로 확인합니다.이것은 GNU 확장이며 BSD 시스템에서는 사용할 수 없습니다.Mac을 실행하는 경우 홈브루를 사용하여 GNU를 설치할 수 있습니다.coreutils그리고 이것을 …로 대체합니다.

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

저는 이것들을 모두 시도했지만 아무 것도 작동하지 않았습니다.하나는 매우 가까웠지만, 그것은 그것을 심하게 부수는 작은 벌레를 가지고 있었습니다; 그들은 그 길을 따옴표로 포장하는 것을 잊었습니다.

또한 많은 사람들이 당신이 셸에서 스크립트를 실행하고 있다고 가정하기 때문에, 당신이 새 스크립트를 열면 그것이 당신의 집으로 기본 설정된다는 것을 잊어버립니다.

크기에 대해 이 디렉터리를 사용해 보십시오.

/var/No one/Thought/About Spaces Being/In a Directory/Name/And Here's your file.text

이렇게 하면 실행 방법과 위치에 관계없이 올바르게 실행할 수 있습니다.

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

실제로 유용하게 사용하려면 실행 중인 스크립트의 디렉터리로 변경하는 방법은 다음과 같습니다.

cd "`dirname "$0"`"

사용해 보십시오.

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

는 e-satis 및 3bcdnlklvc04a 솔루션에 대한 약간의 수정입니다.

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

이것은 그들이 나열한 모든 경우에 여전히 효과가 있을 것입니다.

이렇게 하면 방지할 수 있습니다.popdpushdkonsolebox 입니다.

저는 다음과 같은 것을 사용합니다.

# 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

GNU가 있는 의 .readlink Linux예: Linux):

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

사용할 필요가 없습니다.BASH_SOURCE 때에$0스크립트 파일 이름을 포함합니다.

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

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

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

스크립트 정보를 가져오는 간단한 방법은 다음과 같습니다.

폴더 및 파일:

    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" )" )"

만약 당신이 가지고 있다면.~/bin에 있는 $PATH,당신은 가지고 있다A이 디렉토리 안에 있습니다.스크립트의 소스가 됩니다.~/bin/lib/B은 포함스있크알원스상위대치습다고니를에서 된 위치를 .lib하위 디렉토리이지만 사용자의 현재 디렉토리에 상대적인 위치는 아닙니다.

과 같은됩니다.A):

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

사용자가 어디에 있는지, 스크립트를 어떻게 부르는지는 중요하지 않습니다.이것은 항상 작동할 것입니다.

저는 주어진 답변들 중 많은 것들을 비교했고, 좀 더 간결한 해결책들을 생각해냈습니다.이것들은 당신이 좋아하는 다음의 조합에서 발생하는 모든 미친 에지 사례를 처리하는 것처럼 보입니다.

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

리눅스에서이라면 리눅스를 하는 것으로 .proc중인 스크립트의 핸현실대중완해의소결다찾니입솔좋루션은위가다장한니가킵리소를기각스링서크는들에세션화형은스된를전히재행인크트립스대▁points▁handle▁of▁(▁link▁the)./dev/pts/X):

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

이것은 약간의 추악함을 가지고 있지만, 수정은 작고 이해하기 쉽습니다.bash primitive만 사용하는 것은 아니지만 작업을 상당히 단순화하기 때문에 괜찮습니다.echo X을 추가합니다.X 이름의 까지, 매개 변수 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "${VAR%X}줄의 끝에서 그것을 제거합니다.X.왜냐면readlink자체의 새로운 줄을 추가합니다(이전의 속임수가 아니라면 일반적으로 명령 대체에서 사용됨). 우리도 그것을 제거해야 합니다.이 작업은 다음을 사용하여 가장 쉽게 수행할 수 있습니다.$''인용체, 다과같탈시출사수있다습니용퀀할과 할 수 입니다.\n새 줄을 나타냅니다. 이렇게 하면 쉽게 이름이 잘못된 디렉터리와 파일을 만들 수 있습니다.

은 Linux에서 중인 데 한 내용을 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""proc파일 시스템을 원하는 대로 사용할 수 있습니다. 또는 다른 파일의 완전히 해결된 경로를 찾으려는 경우 아래 코드가 유용할 수 있습니다.위의 원라이너에서 약간 수정한 것에 불과합니다.한 디렉토리 이름을 , 을 둘 다 이 좋습니다.ls그리고.readlink다합보다▁,▁is.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"

제가 이걸 가지고 있는 것 같아요.저는 파티에 늦었지만, 어떤 사람들은 이 실타래를 발견하면 여기에 있는 것을 고마워할 것이라고 생각합니다.코멘트에는 다음 사항이 설명되어야 합니다.

#!/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 -- "${BASH_SOURCE[0]}")" && pwd -P)"

과 같은 합니다.realpath또는readlink를 사용할 수 없습니다(운영 체제에 따라 다름).

에서는 고: Bash서는을사것좋습다니이는용하참에를 사용하는 것이 .${BASH_SOURCE[0]}$0 때 수 .source/.).

또는 Bash에서 다음 기능을 시도할 수 있습니다.

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

이 함수는 하나의 인수를 사용합니다.에 이미 경로가 하고, 인쇄합니다.$PWD+ 인수 + filename 없음)./접두사).

관련:

언급URL : https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script

반응형