소스 쉘 스크립트의 위치 찾기

소스 쉘 스크립트의 위치 찾기

소스 쉘 스크립트가 해당 위치를 알고 있을 수 있습니까? 나는 읽었다소스 셸 스크립트의 경로 결정그러나 POSIX 셸을 사용하는 경우 대답은 bash합계와 실패에 중점을 둡니다.tcsh$0또한 해결책이 아니며 잘못된 결과가 발생합니다..

솔루션이 100% 신뢰할 수 있을 필요는 없습니다. 경로에 하드 링크나 기호 링크가 포함될 가능성이 없습니다.

# sourcing the script should yield the absolute path to the script
. somedir/thescript

# within “thescript”
-> /tmp/foo/bar/somedir

일부 배경:bin스크립트는 기존 애플리케이션의 일부이며 소스 스크립트(아키텍처에 따라 다름)와 관련된 알려진 위치의 디렉터리에 수십 개의 바이너리 파일을 포함합니다. 응용 프로그램을 사용하려면 사용자는 응용 프로그램의 바이너리가 현재 셸(어떤 셸인지에 관계없이)에서 쉽게 호출될 수 있도록 bin스크립트에 디렉터리를 추가해야 합니다.PATH

답변1

POSIX 사양에 대한 확장을 제공하는 셸을 사용하지 않으면 소스 스크립트의 위치를 ​​사용할 수 없습니다. 다음 코드 조각을 사용하여 테스트할 수 있습니다.

env -i PATH=/usr/bin:/bin sh -c '. ./included.sh' | grep included

included.sh포함 하는

echo "$0"
set

bash에서 소스 스크립트의 이름은 in 입니다 $BASH_SOURCE. zsh에서는(sh 또는 ksh 호환 모드가 아닌 zsh 호환 모드에서) in입니다 $0(함수에서는 $0함수 이름입니다). pdksh 및 dash에서는 사용할 수 없습니다. ksh93에서 이 방법은 솔루션을 표시하지 않지만 포함된 스크립트의 전체 경로는 ${.sh.file}.

bash 또는 ksh93이 필요하거나 zsh이면 충분하다면 다음 코드 조각을 사용할 수 있습니다.

if [ -n "$BASH_SOURCE" ]; then
  this_script=$BASH_SOURCE
elif [ -n "$ZSH_VERSION" ]; then
  setopt function_argzero
  this_script=$0
elif eval '[[ -n ${.sh.file} ]]' 2>/dev/null; then
  eval 'this_script=${.sh.file}'
else
  echo 1>&2 "Unsupported shell. Please use bash, ksh93 or zsh."
  exit 2
fi

셸에서 열린 파일을 보면 스크립트의 위치를 ​​추측할 수 있습니다. 실험적으로 이는 dash 및 pdksh에서는 작동하는 것으로 보이지만 bash 또는 ksh93에서는 작동하지 않는 것으로 보입니다. bash 또는 ksh93에서는 적어도 짧은 스크립트에서 실행할 때 이미 스크립트 파일을 닫습니다.

  open_file=$(lsof -F n -p $$ | sed -n '$s/^n//p')
  if [ -n "$open_file" ]; then
    # best guess: $open_file is this script
  fi

스크립트가 리디렉션을 사용하는 복잡한 스크립트에서 생성된 경우 가장 높은 번호의 설명자가 있는 파일이 아닐 수도 있습니다. 열려 있는 파일을 순환할 수도 있습니다. 그러나 이것이 작동한다고 보장되는 것은 아닙니다. 소스 스크립트를 찾는 신뢰할 수 있는 유일한 방법은 bash, ksh93 또는 zsh를 사용하는 것입니다.


인터페이스를 변경할 수 있는 경우 스크립트를 가져오는 대신 스크립트가 eval호출자에게 전달될 셸 조각을 인쇄하도록 합니다. 이는 환경 변수를 설정하는 스크립트가 일반적으로 수행하는 작업입니다. 이를 통해 호출자의 셸 및 셸 구성 변경과 관계없이 스크립트를 작성할 수 있습니다.

#!/bin/sh
FOO_DIR=$(dirname -- "$0")
cat <<EOF
FOO_DIR='$(printf %s "$FOO_DIR" | sed "s/'/'\\''/g")'
PATH="\$PATH:$FOO_DIR/bin";
export FOO_DIR PATH
EOF

발신자에서:eval "`/path/to/setenv`"

답변2

Gilles의 답변에 추가하면 이것이 얼마나 정확한지는 모르겠지만 항상 BusyBox를 사용하여 this_script를 if $0 = ash가리키는 것 같습니다./proc/$$ interface/proc/$$/fd/11

(나처럼) 이 페이지를 탐색하는 사람들에게 잠재적인 답변으로 이것을 제공합니다.

마지막 답변은 삭제되었습니다. 따라서 이 작업에 대한 나의 주장은 4개의 다른 하드웨어 플랫폼(x86, ARM, XLP 및 powerpc)에서 테스트되었습니다. 모두가 동일한 fd/11 답변을 제공합니다. 읽기 링크는 /proc/$$/fd/11내 스크립트를 생성합니다.

앤디

관련 정보