내가 여기에서 요구하는 것은 매우 정통 / 비 전통적 / 위험 중 하나이거나 Google fu 기술이 제대로 작동하지 않습니다 …
A의 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
바람직하게는 플래그 변수를 설정하기 위해 호출자 스크립트가 필요없는 솔루션을 찾고 있습니다.
편집 : 스크립트를 소싱하고 실행하는 것의 차이점 , 사용중인 스크립트 의 차이를 구별 할 수 있는지 여기에서 찾으려고합니다 .
답변
예-$ 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
답변
@DarkHeart의 답변을 환경 변수와 결합 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
답변
방금 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을 빼서 마지막 항목을 얻습니다.
이 세 함수는 파이썬과 유사한 함수 스택 추적을 생성하는 데 함께 사용 되며이 모든 기능이 어떻게 작동하는지 더 잘 알 수 있습니다 …
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는 마치 3 차원 배열 인 것처럼 bash에 의해 유지 관리되는 3 개의 배열입니다.
답변
배열 계산이 신뢰할 수없는 것처럼 보이고 source
점 ( .
)을 사용하는 것이 매우 일반적이기 때문에 source
키워드를 사용하기 때문에 사용 하지 않았다고 가정해야합니다 .
예를 들어, 다음을 포함하는 sourced.sh
스크립트의 경우 echo $0
:
$ . sourced.sh
bash
$ source sourced.sh
bash
$ chmod +x sourced.sh
$ ./sourced.sh
./sourced.sh
$ cat ./sourced.sh
echo $0
비교 솔루션이 더 효과적이라고 제안했습니다.
답변
대화식 쉘 에서 소싱 할 때도 작동하는 한 가지 방법 :
if [ $BASH_LINENO -ne 0 ]; then
some_function;
fi
BASH_LINENO
변수는 호출 함수에서 실행 된 모든 라인으로 배열된다. 스크립트를 직접 호출하거나 줄 번호에 해당하는 정수는 0이됩니다.