Bash: Accessing function call stack in trap function

basherror handlingfunctiontrap:

Working on a bash function call stack trace…

Script traps errors and runs a callStack() function. But on trapping, It always shows a call stack for the callStack() function itself instead of the function where the trap occurred as in …

/share/sbin/zimdialog: line 647: status: command not found
    Function call stack ( command.function() ) ...
      /share/sbin/zimdialog.main()
        /share/sbin/include.callStack()

Looking to get a stack trace that includes the errantFunction() like…

/share/sbin/zimdialog: line 647: status: command not found
    Function call stack ( command.function() ) ...
      /share/sbin/zimdialog.main()
        /share/sbin/zimdialog.errantFunction()
          /share/sbin/include.callStack()

The trap is coded as…

trap callStack HUP INT QUIT TERM ERR

The callStack() function is coded as…

function callStack () {
  { isNotNull "$1" && isHelp "$1"; } && {
    helpShow 'callStack
    Diagnostics regarding where the call to this function came from'
    return
  }
  local T="${T}  "
  local STACK=
  i=${#FUNCNAME[@]}
  ((--i))
  printf "${T}Function call stack ( command.function() ) ...\n" >&2
  T="${T}  "
  while (( $i >= 0 ))
  do
    STACK+="${T}${BASH_SOURCE[$i]}.${FUNCNAME[$i]}()\n"
    T="${T}  "
    ((--i))
  done
  printf "$STACK" >&2
}

Supplemental: set -E, etc. not working

In /share/sbin/gshlib

set -e
set -E
set -T
shopt -s extdebug

trap $(callStack) ERR

function initialize () {
    :
  logstatus                         #<<< ERROR FOR TESTING trap
}
export -f initialize

Misnaming logStatus to logstatus within /share/sbin/gshlib.initialize() to spring the trap ERR, the best I get is…

    Function call stack ...
    | /share/sbin/archive.main()
    |   /share/sbin/include.include()
    |     /share/sbin/gshlib.source()
    |       /share/sbin/include.callStack()
/share/sbin/gshlib: line 109: logstatus: command not found

What I'm looking to get is…

    Function call stack ...
    | /share/sbin/archive.main()
    |   /share/sbin/include.include()
    |     /share/sbin/gshlib.source()
    |       /share/sbin/gshlib.initialize()
    |         /share/sbin/include.callStack()
/share/sbin/gshlib: line 109: logstatus: command not found

Best Answer

You need to set -E (or set -o errtrace) so that the trap ERR is inherited by called functions.

Once you do that, you'll probably find that you'll get a cascading error report, since each function in the call stack will be terminated (with a non-zero exit code) by the script error.

ERR is not triggered by invocation of a shell function in a context where failure is not considered fatal (like if or while). In such a context, the stack trace will probably not appear, although I'm not sure how version-specific that is.

Related Question