1. 23
  1. 3

    FUNCNAME is another good one.

    An array variable containing the names of all shell functions currently in the execution call stack.

    When you need it, you’ll be glad it’s there.

    1. 10

      It can make for some pretty excellent stack traces from complicated (even multi-file) bash-based programs; e.g.,

      $ ./track.sh 
      I failed!
        at make_failure (file "common.sh" line 3)
        at d (file "./track.sh" line 43)
        at c (file "./track.sh" line 38)
        at b (file "./track.sh" line 33)
        at a (file "./track.sh" line 28)
        at main (file "./track.sh" line 54)
      

      From the source files:

      $ nl -ba < common.sh
           1	function make_failure {
           2	    echo "I failed!"
           3	    false
           4	}
      
      $ nl -ba < track.sh
           1	#!/bin/bash
           2	
           3	. "common.sh"
           4	
           5	function stack_trace
           6	{
           7	    set +o xtrace
           8	    set +o errexit
           9	    set +o errtrace
          10	    trap '' ERR
          11	
          12	    for (( i = 0; i < ${#FUNCNAME[@]}; i++ )); do
          13	        if [[ "${FUNCNAME[i]}" == stack_trace ]]; then
          14	            continue
          15	        fi
          16	        if (( i > 0 )); then
          17	            line="${BASH_LINENO[$((i - 1))]}"
          18	        else
          19	            line="${LINENO}"
          20	        fi
          21	        printf '  at %s (file "%s" line %d)\n' "${FUNCNAME[i]}" \
          22	            "${BASH_SOURCE[i]}" "${line}"
          23	    done
          24	}
          25	
          26	function a
          27	{
          28	    b
          29	}
          30	
          31	function b
          32	{
          33	    c
          34	}
          35	
          36	function c
          37	{
          38	    d
          39	}
          40	
          41	function d
          42	{
          43	    make_failure
          44	}
          45	
          46	#
          47	# Install our error handling trap, so that we can have stack traces on
          48	# failures.  We set "errtrace" so that the ERR trap handler is inherited
          49	# by each function call.
          50	#
          51	trap stack_trace ERR
          52	set -o errtrace
          53	
          54	a
      
    2. 1

      You won’t believe number four!

      1. 0

        In Zsh, TMOUT works as well but differently from Bash (which exits with status 0) the shell exits with error status code 14 (the numeric value of SIGALRM). However that can be overridden with a trap function – for example:

        TRAPALRM() {
          echo 'zsh: logging out after timeout'
          exit 0
        }