Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The Bash EXIT trap is a built-in shell mechanism that registers a command or function to execute automatically when the shell process terminates. It intercepts the shell-internal pseudo-signal EXIT (also represented as signal 0), ensuring the specified code evaluates during the teardown phase of the shell execution lifecycle.

Syntax

The trap builtin requires two primary arguments: the payload (a string containing the command or function to execute) and the signal specification (EXIT or 0).

# Standard syntax using the EXIT pseudo-signal
trap 'command_or_function' EXIT


# Alternative syntax using the numeric equivalent
trap 'command_or_function' 0


# Clearing an existing EXIT trap
trap - EXIT

Trigger Conditions

The EXIT trap is invoked under the following conditions:
  • Normal Termination: The shell reaches the end of the script (EOF).
  • Explicit Termination: An exit builtin is executed anywhere within the script.
  • Errexit Termination: The script terminates prematurely due to the set -e (errexit) option encountering a non-zero exit status.
The EXIT trap will not trigger under these conditions:
  • Untrapped Fatal Signals: The shell receives a termination signal such as SIGINT (Ctrl+C), SIGTERM, or SIGHUP that is not explicitly trapped. The shell terminates immediately and bypasses the EXIT trap.
  • Uncatchable Signals: The process is terminated by SIGKILL (e.g., kill -9) or suspended by SIGSTOP, both of which bypass user-space signal handling entirely.
  • Process Replacement: The shell process is replaced entirely using the exec builtin. The original shell ceases to exist, taking its trap registrations with it.
  • Hardware/System Faults: A fatal segmentation fault or hardware-level interruption occurs.

Interaction with Explicit Signal Traps

Because untrapped fatal signals bypass the EXIT trap, developers must explicitly trap signals like INT and TERM to ensure the EXIT payload executes during an interruption. If a signal is explicitly trapped, the shell executes the trap payload and then resumes execution of the script from the point of interruption. To force termination, the signal trap payload must explicitly invoke the exit builtin. Invoking exit inside a signal trap immediately triggers the EXIT trap. Binding the same function to both EXIT and termination signals is a common anti-pattern. It can lead to double-execution if the handler calls exit, or it can force a successful script to exit with a failure code if the handler hardcodes an error status. The correct pattern isolates the payload in the EXIT trap and binds termination signals to an exit command, which safely routes the termination through the EXIT trap.

# ANTI-PATTERN: Binds the same handler to EXIT and signals.

# If the script finishes successfully, it still exits with 130.
handler() {
    # ... payload logic ...
    exit 130 
}
trap 'handler' EXIT INT TERM


# CORRECT PATTERN: Bind the payload only to EXIT. 

# Bind signals to explicitly exit, which then triggers the EXIT trap.
handler() {
    # ... payload logic ...
}
trap 'handler' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM

Execution Context and State

When the EXIT trap fires, it executes within the current shell environment, not a subshell. This means the trap payload retains full access to the script’s global variables, functions, and file descriptors exactly as they existed at the moment of termination. If multiple EXIT traps are defined sequentially in a script, the shell only honors the most recently defined trap. A new trap ... EXIT declaration silently overwrites the previous one.

Exit Status Behavior

By default, a Bash script returns the exit status of the last command executed before the trap was triggered. The execution of the trap itself does not alter the script’s final exit status, even if commands within the trap fail.
trap 'echo "Trap executed"' EXIT
false # Script will exit with status 1, despite the trap succeeding
To override this behavior, an explicit exit <N> command must be invoked inside the trap payload. This forces the shell to discard the original exit status and terminate with the status provided by the trap.
trap 'exit 0' EXIT
false # Script will exit with status 0, overridden by the trap

Subshell Inheritance

EXIT traps are bound to the specific shell process in which they are defined. Subshells (created via command substitution $(...), grouping (...), or background processes &) do not inherit the EXIT trap from their parent shell. If an EXIT trap is required for a subshell’s termination, it must be explicitly declared within that subshell’s execution block.
Master Bash with Deep Grasping Methodology!Learn More