Sometimes Bash quietly hides features that make you stop, blink, and say:

“Wait… that’s been there the whole time?!

This post is about one of those features: Bash knows which function you’re in — and even keeps a call stack. You can use it for logging, debugging, and some truly delightful shell wizardry.


Printing the Name of the Current Function

If you’re inside a Bash function and want to know its name, Bash gives it to you for free via the FUNCNAME array.

myfunc() {
    echo "I was called as: ${FUNCNAME[0]}"
}

Running it:

myfunc

Outputs:

I was called as: myfunc

What’s FUNCNAME?

  • FUNCNAME[0] → the current function
  • FUNCNAME[1] → the caller
  • FUNCNAME[2] → the caller’s caller

… and so on

Yes — Bash has a call stack.

Seeing Who Called You

Let’s demonstrate:

outer() {
    inner
}

inner() {
    echo "Current: ${FUNCNAME[0]}"
    echo "Called by: ${FUNCNAME[1]}"
}

Output:

Current: inner
Called by: outer

This alone is already hugely useful for debugging and logging.

A Reusable Logging Helper

Here’s where it gets fun. You can write a single helper function that logs who called it:

log() {
    echo "[${FUNCNAME[1]}] $*"
}

do_thing() {
    log "starting"
    sleep 1
    log "done"
}

Output:

[do_thing] starting
[do_thing] done

No hardcoded function names. No copy/paste mistakes. Chef’s kiss.

Add Line Numbers for Instant Context

Bash also gives you line numbers via BASH_LINENO.

log() {
    echo "[${FUNCNAME[1]}:${BASH_LINENO[0]}] $*"
}

Output now looks like:

[do_thing:6] starting
[do_thing:8] done

At this point your shell scripts are starting to feel… civilised.

Printing a Call Stack (Yes, Really)

Want to see how you got here? Here’s a simple stack trace function:

stacktrace() {
    echo "Call stack:"
    for ((i=1; i<${#FUNCNAME[@]}; i++)); do
        echo "  ${FUNCNAME[$i]}:${BASH_LINENO[$((i-1))]}"
    done
}

Example usage:

oops() {
    stacktrace
}

a() { b; }
b() { oops; }

a

Output:

Call stack:
  oops:2
  b:5
  a:4

Tell me that’s not beautiful.

Automatic Stack Traces on Errors (Dark Magic)

You can even hook this into Bash’s error handling.

Add this to your .bashrc or script:

set -o errtrace
trap 'echo "💥 Error in ${FUNCNAME[0]} at line ${LINENO}"; stacktrace' ERR

Now, when a command fails, Bash prints:

  • the function it failed in
  • the line number
  • the full call stack

Congratulations — you’ve invented poor man’s exceptions.

Caveats

  • This is Bash-specific
  • It won’t work in POSIX sh
  • It does work in interactive shells and scripts
  • Zsh has similar features, but with different variables

Final Thoughts

Once you start using FUNCNAME and BASH_LINENO, scripts without them feel… naked.

If you write anything non-trivial in Bash — especially helpers, install scripts, or admin tooling — this stuff is pure gold.

Happy shell hacking 🐚✨