次の関数は、オプションのデバッグ、コンテキスト・ヘルプなどを処理するために、他のすべての関数の最初の行として呼び出されます。したがって、ある関数を呼び出してから別の関数を呼び出すと、循環参照が発生する可能性があり、通常は発生します。
機能を失うことなく循環参照を回避するには?
function fnInit () {
###
### on return from fnInit...
### 0 implies "safe to continue"
### 1 implies "do NOT continue"
###
#
local _fn=
local _msg=
#
### handle optional debugging, context sensitive help, etc.
#
[[ "$INSPECT" ]] && { TIMELAPSE= ...; }
### fnInit --inspect
#
[[ "$1" == --help ]] && { ... ; return 1; }
### fnInit --help
# :
# :
return 0
}
答え1
関数 fnInit() (たとえば、現在の関数 - ${FUNCNAME[0]}) も関数呼び出しスタックのより高い場所に表示される場合は、救済策を講じてください。
以下の結果バージョンでは...
- $_fnaは、それを呼び出した関数(レベル1以上)から始まり、関数呼び出しスタックにスペースで区切られた関数名のリストを含む文字列です。
- このイディオムは
"${_fna/${FUNCNAME[0]}/}"
$_fna から現在の関数名を減算します。 [[ "${_fna/${FUNCNAME[0]}/}" != "${_fna}" ]]
減算結果が元の結果と等しい場合(何も減算しない)、比較結果はtrue(0)を返します。- リスト処理制御演算子は、
&&
前のコマンド()の戻りコードがtrue(0)の場合にのみ、次の[[ ... ]]
コマンドが実行されることを意味します。 { return 0; }
ここでは1つのコマンドしか実行されないため、return()の周りの中括弧はオプションです。しかし、彼らは必須です他のすべてのケースでは、一貫性のために通常置きます。それらが存在しない場合、演算子の優先順位のため、このような操作は[[ ... ]] && dosomething; return 0
期待通りに真の場合にのみ実行されます。dosomething
[[ ... ]]
しかし、それは常に実装されますreturn 0
。Bashはこれを次のように読みます...[[ ... ]] && dosomething return 0
fnInit()
各関数呼び出しは一度だけ処理されます。
function fnInit () {
###
### on return from fnInit...
### 0 implies "safe to continue"
### 1 implies "do NOT continue"
###
local _fna="${FUNCNAME[*]:1}"; [[ "${_fna/${FUNCNAME[0]}/}" != "${_fna}" ]] && { return 0; }
### Detect circular reference
### Is function in the function call stack more than once?
###
### Seems like the following should work but it does not...
### if [[ "${FUNCNAME[*]:1/$FUNCNAME/}" != "${FUNCNAME[*]:1}" ]]; then ...
### It appears to fail silently and exit the script so neither 'then'
### nor 'else' branch executes.
### Why?
### per http://unix.stackexchange.com/q/186942/27437...
### In general, you can't use multiple variable expansion modifiers
### in the same expression. – Barmar
###
### Solution:
### Store the array into a temporary string variable.
###
#
local _fn=
local _msg=
#
### handle optional debugging, context sensitive help, etc.
#
[[ "$INSPECT" ]] && { TIMELAPSE= ...; }
### fnInit --inspect
#
[[ "$1" == --help ]] && { ... ; return 1; }
### fnInit --help
# :
# :
return 0
}
答え2
通常、これは状態変数(フラグ)を確認して設定することによって行われます。まるで…
function fnInit
{
[[ -z ${this_init_state} ]] || return 0
this_init_state=1
# rest of your code
}
(初期化関数が別のモジュールにある場合は、dotコマンドを使用してそのモジュールを取得します。)