Bash 4.1.0에서 순환 참조 감지

Bash 4.1.0에서 순환 참조 감지

다음 함수는 선택적 디버깅, 상황에 맞는 도움말 등을 처리하기 위해 다른 모든 함수의 첫 번째 줄로 호출됩니다. 따라서 한 함수를 호출한 다음 다른 함수를 호출하면 순환 참조가 발생할 수 있으며 일반적으로 발생합니다.

기능을 잃지 않고 순환 참조를 피하는 방법은 무엇입니까?

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; }여기서는 하나의 명령만 실행되므로 return( ) 주위의 중괄호는 선택 사항입니다. 하지만그들은 필수입니다다른 모든 경우에는 일관성을 위해 일반적으로 넣습니다. 그것들이 없으면 연산자 우선 순위로 인해 이와 같은 작업은 [[ ... ]] && dosomething; return 0예상대로 true인 경우에만 실행됩니다.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 명령을 사용하여 해당 모듈을 가져옵니다.)

관련 정보