Acabei de criar o mesmo tipo de script de biblioteca que funciona muito como o BusyBox. Nele, uso a seguinte função para testar se está sendo originada ...
function isSourced () {
[[ "${FUNCNAME[1]}" == "source" ]] && return 0
return 1
}
O array FUNCNAME mantido pelo Bash é essencialmente uma pilha de chamadas de função. $FUNCNAME
(ou ${FUNCNAME[0]}
) é o nome da função atualmente em execução. ${FUNCNAME[1]}
é o nome da função que o chamou e assim por diante.
O item mais acima é um valor especial para o próprio script. Ele conterá ...
- a palavra "fonte" se o script estiver sendo fornecido
- a palavra "main" se o script está sendo executado E o teste está sendo feito dentro de uma função
- "" (null) se o script estiver sendo executado E o teste estiver sendo feito fora de qualquer função, isto é ... no nível do próprio script.
A função acima só funciona quando chamada no nível do script (que é tudo que eu precisava). Ele falharia se chamado de dentro de outra função porque o número do item da matriz estaria errado. Para fazê-lo funcionar em qualquer lugar, é necessário encontrar o topo da pilha e testar esse valor, o que é mais complicado.
Se você precisar, você pode obter o número do item da matriz do "topo da pilha" com ...
local _top_of_stack=$(( ${#FUNCNAME[@]} - 1 ))
${#FUNCNAME[@]}
é o número de itens na matriz. Como uma matriz baseada em zero, subtraímos 1 para obter o último item #.
Estas três funções são usadas juntas para produzir um rastreamento de pilha de função similar ao do Python e podem lhe dar uma idéia melhor de como tudo isso funciona ...
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
}
Note que FUNCNAME, BASH_SOURCE e BASH_LINENO são 3 arrays mantidos pelo bash como se fossem um array tridimensional.