Shell scripts often include multiple functions, making it challenging to track which functions are running and whether they complete successfully. Automatically printing each function's name and its exit status as it executes helps with debugging and ensures that failures are caught early. This guide explains how to set up a trap in your shell script to display this information in real time.

Using Bash Traps and DEBUG/RETURN Signals

Step 1: Start by defining a shell function that will print the current function name and its exit status. Place this function at the top of your script for easy reference. The BASH_COMMAND and FUNCNAME arrays help identify the current function context.


print_func_status() {
    local func="${FUNCNAME[1]}"
    local status="$?"
    echo "Function: $func exited with status $status"
}
    

This function uses FUNCNAME[1] to get the name of the function that just returned, and $? to get its exit status.

Step 2: Set a trap for the RETURN signal, which fires every time a function returns. Add this line after your print_func_status function definition:


trap print_func_status RETURN
    

This ensures that print_func_status runs after every function finishes, printing its name and exit status.

Step 3: Write your script's functions as usual. You do not need to modify them individually, as the trap will run automatically after each function returns.


foo() {
    echo "This is foo"
    return 0
}

bar() {
    echo "This is bar"
    return 1
}
    

When you call foo or bar, the trap prints their names and exit statuses:


foo
bar
    

Sample output:


This is foo
Function: foo exited with status 0
This is bar
Function: bar exited with status 1
    

Step 4: If your script uses nested functions or you want more detail, you can expand the print_func_status function to print call stack information or timestamps as needed.


Alternative: Using DEBUG Trap for More Granular Tracing

For even more detailed tracing, such as printing the function name before each command executes, you can use the DEBUG trap. However, this approach may produce much more output and can slow down script execution.

Step 1: Define a function to print the current command and function name:


trace_command() {
    local func="${FUNCNAME[1]}"
    local cmd="$BASH_COMMAND"
    echo "Function: $func running command: $cmd"
}
    

Step 2: Set the DEBUG trap:


trap trace_command DEBUG
    

This will print the function name and command before each command is executed, which is useful for in-depth debugging but may be too verbose for general use.


Setting traps in your shell scripts to automatically print function names and exit statuses streamlines debugging and quickly identifies where failures occur. Adjust the verbosity to your needs, and remember to remove or comment out these traps in production scripts to avoid cluttering your logs.