BusyBoxと同じように機能する同じ種類のライブラリスクリプトを作成しました。その中で、次の関数を使用して、ソースになっているかどうかをテストします...
function isSourced () {
[[ "${FUNCNAME[1]}" == "source" ]] && return 0
return 1
}
Bashが管理するFUNCNAME配列は、本質的に関数呼び出しスタックです。$FUNCNAME
(または${FUNCNAME[0]}
)は、現在実行中の関数の名前です。${FUNCNAME[1]}
それを呼び出した関数の名前などです。
一番上の項目は、スクリプト自体の特別な値です。それが含まれます...
- スクリプトがソースされている場合、「ソース」という言葉
- スクリプトが実行され、テストが関数内から実行されている場合、「メイン」という言葉
- ""(null)スクリプトが実行されており、テストが関数の外部で実行されている場合、つまり、スクリプト自体のレベルで実行されている場合。
上記の関数は、実際にはスクリプトレベルで呼び出された場合にのみ機能します(必要なのはこれだけです)。配列項目番号が間違っているため、別の関数内から呼び出された場合は失敗します。どこでも動作させるには、スタックの最上位を見つけてその値をテストする必要がありますが、これはより複雑です。
必要な場合は、「スタックの最上部」の配列項目番号を取得できます...
local _top_of_stack=$(( ${#FUNCNAME[@]} - 1 ))
${#FUNCNAME[@]}
配列内のアイテムの数です。ゼロベースの配列として、1を減算して最後のitem#を取得します。
これら3つの関数は、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によって1つの3次元配列であるかのように維持される3つの配列であることに注意してください。