소스 스크립트가 실행되지 않도록 정의하는 방법


40

사용자가 source실행하지 않고 쉘 스크립트를 정의하고 있습니다.

예를 들어 파일 확장자를 통해 이러한 경우를 사용자에게 암시하는 기존의 또는 지능적인 방법이 있습니까?

파일 자체에 작성할 수있는 셸 코드가 있습니까? 그러면 소스 대신 실행되는 경우 메시지를 표시하고 종료되어 사용자가이 명백한 실수를 피할 수 있도록 도와 줄 수 있습니까?


1
따라서 사용자가 x명령을 포함 하는 한 줄짜리 쉘 스크립트를 작성하는 . your-script-to-be-sourced경우 괜찮지 만 실행하려면 bash your-script-to-be-sourced금지해야합니까? 이 제한의 요점은 무엇입니까?
user1934428

8
물론입니다. 이것은 많은 env변수 를 계산하고 사실상의 스크립트 출력 으로 남겨 두는 스크립트의 경우 정상입니다 . 초보자가 퍼즐을 실행하면 며칠 동안 멈출 수 있습니다.
kubanczyk

답변:


45

bash를 실행하고 있다고 가정하면, 소스가 있지만 실행하지 않으려는 스크립트의 시작 부분에 다음 코드를 넣으십시오.

if [ "${BASH_SOURCE[0]}" -ef "$0" ]
then
    echo "Hey, you should source this script, not execute it!"
    exit 1
fi

bash 아래 ${BASH_SOURCE[0]}에는 소스가 실행 중인지 또는 실행 중인지에 관계없이 쉘이 읽고있는 현재 파일의 이름이 포함됩니다.

대조적으로, $0현재 실행중인 파일의 이름입니다.

-ef이 두 파일이 같은 파일인지 테스트합니다. 그러한 경우 사용자에게 알리고 종료합니다.

POSIX 도 -ef아닙니다 BASH_SOURCE. -efksh, yash, zsh 및 Dash가 지원 하지만 BASH_SOURCEbash가 필요합니다. 에서zsh , 그러나, ${BASH_SOURCE[0]}로 대체 될 수있다 ${(%):-%N}.


2
간단히 echo "Usage: source \"$myfile\""
kubanczyk

6
@kubanczyk source은 (는) 휴대 할 수 없습니다. 이 답변은 배쉬에 따라 다르지만 그렇게 나쁘지는 않지만 휴대용을 사용하는 것이 좋습니다.
gronostaj

33

실행 파일이 아닌 파일을 소스로 만들 수는 있지만 실행할 수 없으므로 첫 번째 방어선으로 실행 플래그를 설정하지 않는 것이 좋습니다.

편집 : 방금 비틀었던 트릭 : shebang을 쉘 인터프리터가 아닌 실행 파일로 /bin/false만들고 스크립트에서 오류를 반환합니다 (rc! = 0)

#!/bin/false "This script should be sourced in a shell, not executed directly"

7
그러나 실행 불가능한 파일은 다음을 통해 여전히 실행될 수 있습니다 bash somefile.sh.
twalberg

1
당신이 bash(vd perl, python, awk ...)로 그것을 실행할 수 있다는 것을 안다면 , 당신은 소스를 보았고 그것을하지 않는 주석을 보았습니다 :)
xenoid

1
Perl 스크립트는 일반적으로 이름이 somefile.pl이고 Python somefile.pybash somefile.shchmod +x somefile.sh; ./somefile.sh
은로 지정

또한 일부는 Bourne의-등을 포함하는 쉘, bash처음에 시도 할 것이다, execve파일,하지만 실패 할 경우, 그들은 수동으로 파일을 검사하고 수동으로 해석 #!하고 통역을 통해 호출합니다 이것은이 시대의 유산 인 #!순수 사용자 공간이었다가 커널 자체에 의해 처리되는 대신 컨벤션. 나는 생각한다 bash , 적어도 것 없는 비 실행 파일이 작업을 수행하지만 사용자가에서 스크립트를 호출 할 수 있음을 모든 쉘에서 같은 제정신 행동을 기대하는 휴대용 있는지 모르겠어요.
mtraceur

"당신은 당신이 bash는 그것을 실행할 수 있습니다 알고있는 경우"음, 아니, 때때로 사용자는 단지 이외의 껍질이 존재한다는 것을 모르고있다 bash 그것은 bash script.sh위험 할 수 있습니다.
Sergiy Kolodyazhnyy

10

이 Stack Overflow post에 제안 된 몇 가지 방법이 있습니다.이 중 Wirawan Purwantomr.spuratic best가 제안한 함수 기반 방법을 좋아했습니다 .

Wirawan Purwanto가 제안한 가장 강력한 방법 FUNCNAME[1] 은 함수 내 에서 확인 하는 것입니다 .

function mycheck() { declare -p FUNCNAME; }
mycheck

그때:

$ bash sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="main")'
$ . sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="source")'

이 검사의 출력에 상당 caller값, mainsource발신자의 상황을 구별. 를 사용 FUNCNAME[]하면 caller출력 을 캡처하고 구문 분석 할 수 있습니다 . 그래도 로컬 통화 깊이를 알고 계산해야합니다. 스크립트가 다른 함수 나 스크립트 내에서 제공되는 경우 배열 (스택)이 더 깊어집니다. ( FUNCNAME특별한 bash 배열 변수입니다. 호출 스택에 해당하는 연속 인덱스가 있어야합니다 unset.

따라서 스크립트 시작 부분에 추가 할 수 있습니다.

function check()
{
    if [[ ${FUNCNAME[-1]} != "source" ]]   # bash 4.2+, use ${FUNCNAME[@]: -1} for older
    then
        printf "Usage: source %s\n" "$0"
        exit 1
    fi
}
check

7

스크립트를 실행하는 것이 해롭지 않고 쓸모가 없다고 가정하면 추가 할 수 있습니다

return 0 || printf 'Must be sourced, not executed\n' >&2

받는 종료 스크립트. return함수 외부에 파일이 소스되지 않으면 종료 코드가 0이 아닙니다.


3
이것은 0 종료 상태를 리턴합니다. 내가 대신 사용하는 이와 유사한 관용구를 사용해보십시오.return 2>/dev/null; echo "$0: This script must be sourced" 1>&2; exit 1
wjandrea

5

쉘 스크립트를 소싱 할 때 shebang 행은 무시됩니다. 잘못된 shebang을 넣으면 스크립트가 잘못 실행되었음을 사용자에게 경고 할 수 있습니다.

#!/bin/bash source-this-script
# ...

오류 메시지는 다음과 같습니다.

/bin/bash: source-this-script: No such file or directory

(임의의) 인수 이름은 이미 강력한 힌트를 제공하지만 오류 메시지는 여전히 100 % 명확하지 않습니다. 우리는 source-this-script당신의 어딘가에 있는 유틸리티 스크립트로 이것을 고칠 수 있습니다 PATH:

#!/bin/sh
echo >&2 "This script must be sourced, not executed${1:+: }${1:-!}"
exit 1

이제 오류 메시지는 다음과 같습니다.

This script must be sourced, not executed: path/to/script.sh

다른 접근법과의 비교

다른 답변과 비교할 때,이 접근 방식은 각 스크립트에 대한 최소한의 변경 만 필요합니다 (그리고 shebang 행을 사용하면 편집기에서 파일 유형 감지에 도움이되고 쉘 스크립트 언어를 지정하므로 이점도 있습니다). 단점은 다소 불명확 한 오류 메시지이거나 다른 셸 스크립트를 한 번 추가 한 것입니다.

bash path/to/script.sh그래도 @muru 덕분에 명시적인 호출을 막을 수는 없습니다 .


1
또 다른 단점은을 보호하지 못하기 bash some/script.sh때문에 shebang을 무시한다는 것입니다.
muru

4
shebang #!/bin/echo 'You must source this script!'또는 이와 유사한 것을 작성하여 메시지를 더 명확하게 만들 수 있습니다 .
Chris

1
@Chris : 그렇습니다. 그러나 파일 형식 탐지 (예 : Vim)와이 파일이 어떤 셸 방언에 대한 문서를 잃게됩니다. 당신이 이것에 관심이 없다면, 당신의 제안은 실제로 두 번째 대본을 제거 할 것입니다!
Ingo Karkat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.