내가 여기서 묻는 것은 매우 비정통적이거나 틀에 얽매이지 않거나 위험하거나, 아니면 내 Google 기술이 단순히 수준에 미치지 못하는 것입니다...
쉘 스크립트 에서 bash
다른 쉘 스크립트에 의해 선택되었는지 아니면 자체적으로 실행되었는지 쉽게 알 수 있는 방법이 있습니까? 즉, 다음 두 가지 행위를 구별하는 것이 가능한가?
# from another shell script
source myScript.sh
# from command prompt, or another shell script
./myScript.sh
내가 생각하고 있는 것은 bash
소스 코드를 가져올 때 사용할 수 있는 기능이 포함된 유틸리티와 유사한 쉘 스크립트를 만드는 것입니다. 그러나 스크립트가 자체적으로 실행될 때 정의된 함수를 기반으로 작업을 수행하기를 원합니다.이 쉘 스크립트가 일종의 환경 변수를 얻는 것이 가능합니까?
some_function() {
# ...
}
if [ -z "$IS_SOURCED" ]; then
some_function;
fi
바람직하게는 플래그 변수를 설정하기 위해 호출자 스크립트가 필요하지 않은 솔루션을 찾고 있습니다.
편집하다:스크립트를 받는 것과 스크립트를 실행하는 것의 차이점을 알고 있습니다. 가능하다면 여기서 무엇을 알고 싶습니다.차이점을 말해보세요사용되는 스크립트에서 (두 가지 방법으로).
답변1
예 - $0 변수는 실행될 때 스크립트 이름을 제공합니다.
$ cat example.sh
#!/bin/bash
script_name=$( basename ${0#-} ) #- needed if sourced no path
this_script=$( basename ${BASH_SOURCE} )
if [[ ${script_name} = ${this_script} ]] ; then
echo "running me directly"
else
echo "sourced from ${script_name}"
fi
$ cat example2.sh
#!/bin/bash
. ./example.sh
다음과 같이 실행합니다:
$ ./example.sh
running me directly
$ ./example2.sh
example.sh sourced from example2.sh
이는 대화형 셸에서 소스 코드를 가져오는 데 실제로 적합하지 않지만 아이디어는 얻을 수 있습니다(희망합니다).
BASH_SOURCE를 포함하도록 업데이트되었습니다. hjk에게 감사드립니다.
답변2
콤비네이션@심심환경 변수를 사용하여 응답하는 것이 BASH_SOURCE
트릭을 수행하는 것 같습니다.
$ head example*.sh
==> example2.sh <==
#!/bin/bash
. ./example.sh
==> example.sh <==
#!/bin/bash
if [ "$(basename $0)" = "$(basename $BASH_SOURCE)" ]; then
echo "running directly"
else
echo "sourced from $0"
fi
$ ./example2.sh
sourced from ./example2.sh
$ ./example.sh
running directly
편집하다BASH_SOURCE
배열의 요소 수만 세면 이 방법이 더 간단한 해결책인 것 같습니다.
if [ ${#BASH_SOURCE[@]} -eq 1 ]; then echo "running directly"; else echo "sourced from $0"; fi
답변3
방금 BusyBox와 유사한 동일한 유형의 라이브러리 스크립트를 만들었습니다. 여기에서는 다음 함수를 사용하여 가져오는 중인지 테스트합니다.
function isSourced () {
[[ "${FUNCNAME[1]}" == "source" ]] && return 0
return 1
}
Bash가 유지 관리하는 FUNCNAME 배열은 본질적으로 함수 호출 스택입니다. $FUNCNAME
(또는 ${FUNCNAME[0]}
)은 현재 실행 중인 함수의 이름입니다. ${FUNCNAME[1]}
그것을 호출하는 함수의 이름 등입니다.
상위 항목은 스크립트 자체에 대한 특수 값입니다. 그것은 포함됩니다 ...
- 스크립트가 소스인 경우 "source"라는 단어가 표시됩니다.
- 스크립트가 실행되고 테스트가 함수 내에서 수행되는 경우 "main"이라는 단어
- ""(null) 스크립트가 실행되고 테스트가 기능 외부, 즉 스크립트 자체 수준에서 수행되는 경우.
위의 함수는 실제로 스크립트 수준에서 호출될 때만 작동합니다(이것이 제가 필요로 하는 것입니다). 배열 항목 번호가 잘못되므로 다른 함수 내부에서 호출하면 실패합니다. 모든 곳에서 작동하도록 하려면 스택의 맨 위를 찾아 해당 값을 테스트해야 하는데 이는 더 복잡합니다.
필요한 경우 다음 명령을 사용하여 "스택 상단에" 배열 항목 번호를 가져올 수 있습니다.
local _top_of_stack=$(( ${#FUNCNAME[@]} - 1 ))
${#FUNCNAME[@]}
배열의 항목 수입니다. 0부터 시작하는 배열로 1을 빼서 마지막 항목 #을 얻습니다.
이 세 가지 함수는 함께 사용되어 이 모든 것이 어떻게 작동하는지에 대한 더 나은 아이디어를 제공할 수 있는 Python과 유사한 함수 스택 추적을 생성합니다.
function inspFnStack () {
local T+=" "
local _at=
local _text="\n"
local _top=$(inspFnStackTop)
local _fn=${FUNCNAME[1]}; [[ $_fn =~ source|main ]] || _fn+="()"
local i=_top; ((--i))
#
_text+="$i item function call stack for $_fn ...\n"
_text+="| L BASH_SOURCE{BASH_LINENO called from}.FUNCNAME \n"
_text+="| ---------------------------------------------------\n"
while (( $i > 0 ))
do
_text+="| $i ${T}$(inspFnStackItem $i)\n"
T+=" "
((--i))
done
#
printf "$_text\n"
#
return 0
}
function inspFnStackItem () {
local _i=$1
local _fn=${FUNCNAME[$_i]}; [[ $_fn =~ source|main ]] || _fn+="()"
local _at="${BASH_LINENO[$_i-1]}"; [[ $_at == 1 ]] && _at="trap"
local _item="${BASH_SOURCE[$_i]}{${_at}}.$_fn"
#
printf "%s" "$_item"
return 0
}
function inspFnStackTop () {
# top stack item is 1 less than length of FUNCNAME array stack
printf "%d\n" $(( ${#FUNCNAME[@]} - 1 ))
#
return 0
}
FUNCNAME, BASH_SOURCE 및 BASH_LINENO는 bash가 마치 3차원 배열인 것처럼 유지 관리하는 3개의 배열이라는 점에 유의하세요.
답변4
source
계산 배열은 신뢰할 수 없는 것 같고 dot()를 사용하는 것도 .
일반적이며 source
키워드 보다 우선하므로 dot()를 사용한다고 가정해서는 안 된다는 점을 추가하고 싶었습니다 .
예를 들어 sourced.sh
다음만 포함하는 스크립트 의 경우 echo $0
:
$ . sourced.sh
bash
$ source sourced.sh
bash
$ chmod +x sourced.sh
$ ./sourced.sh
./sourced.sh
$ cat ./sourced.sh
echo $0
제안된 비교 솔루션이 더 잘 작동합니다.