Bash Signals and Traps are essential for writing resilient shell scripts. Signals notify processes of events like termination, errors, or interrupts. With traps, you can gracefully handle these signals, ensuring your script exits cleanly and performs necessary cleanup tasks.
By mastering Bash Signals and Traps, you can improve script reliability, manage unexpected interruptions, and ensure that temporary files, resources, and states are handled correctly. Let’s explore how signals work and how traps give you fine-grained control over process behavior.
What Are Bash Signals?
Signals in Bash are system-generated notifications sent to processes. They act as interrupts, allowing the operating system or user actions to interact with running scripts.
Some common Bash signals include:
- INT (Interrupt): Triggered by
Ctrl+C
, used to stop a process. - QUIT (Quit): Triggered by
Ctrl+\
, often for forceful termination. - TERM (Terminate): Requests a process to stop safely.
- HUP (Hangup): Sent when a terminal closes.
- USR1/USR2 (User Signals): Custom-defined signals for scripts.
These signals let you manage process flow, making them especially important in automation, servers, and long-running jobs.
The Trap Command in Bash
The trap command is Bash’s built-in way to handle signals. It lets you define actions that run when a script receives specific signals.
Syntax:
trap 'commands' SIGNAL [SIGNAL ...]
commands
: The action to perform when the signal is received.SIGNAL
: The signal name or number (e.g., INT, TERM).
With traps, you gain direct control over how your script responds, from cleanup tasks to logging or even ignoring signals entirely.
Example: Handling Ctrl+C Gracefully
A common use case for Bash Signals and Traps is handling Ctrl+C (SIGINT) interruptions. Instead of stopping abruptly, you can define a cleanup function.
#!/bin/bash
cleanup() {
echo "Cleaning up temporary files..."
rm -f /tmp/my_temp_file
}
trap cleanup INT # Trap Ctrl+C
echo "Script running. Press Ctrl+C to stop."
sleep 10
When you press Ctrl+C
, the script doesn’t exit immediately. Instead, it runs the cleanup
function first, ensuring a safe exit.
Example: Custom Signal Handling
Bash also supports custom signals like USR1
or USR2
. These are handy when you need inter-process communication.
#!/bin/bash
custom_handler() {
echo "Received USR1 signal!"
}
trap custom_handler USR1
echo "Running script with PID $$"
while true; do
sleep 2
done
To send a signal:
kill -USR1 <PID>
This approach is useful for monitoring, triggering log writes, or performing periodic checks during execution.
Ignoring Signals with Traps
Sometimes you don’t want a signal to stop your script. For example, ignoring SIGQUIT ensures your script keeps running.
trap '' QUIT
Here, the empty string (''
) tells Bash to ignore the signal. This is common in critical automation tasks where accidental interrupts should not terminate execution.
Advanced Trap Usage
Traps in Bash can be dynamic, even nested inside other traps, making scripts more adaptive.
#!/bin/bash
count=1
trap 'echo "First QUIT received!"; count=$((count+1)); trap "echo QUIT trapped $count times" QUIT' QUIT
while true; do
sleep 1
done
In this script, the first QUIT
signal triggers one action, and subsequent signals trigger another. This flexibility makes Bash Signals and Traps powerful for advanced error handling and control.
Using EXIT and ERR Traps
Besides signals, Bash provides EXIT and ERR traps:
- EXIT: Runs when the script ends, whether normally or due to a signal.
- ERR: Runs whenever a command fails (non-zero exit code).
Example:
#!/bin/bash
trap 'echo "Script exited!"' EXIT
trap 'echo "Error occurred!"' ERR
ls /nonexistent_dir # This will trigger ERR
These traps improve debugging and allow you to enforce consistent exit behavior.
Practical Use Cases of Bash Signals and Traps
1. Ensuring Cleanup on Exit
Scripts that create temp files, open sockets, or lock resources should clean up on termination. Traps guarantee no leftover files or zombie processes.
2. Long-Running Background Jobs
Automated scripts or daemons can handle signals gracefully, writing logs or restarting tasks instead of crashing.
3. Logging and Monitoring
Using custom traps like USR1
, you can log memory usage, send metrics, or output debug data without stopping the script.
4. Deployment Scripts
Traps help in stopping deployments safely when aborted midway, ensuring resources are rolled back correctly.
Best Practices for Bash Signals and Traps
- Always use cleanup functions instead of inline commands for clarity.
- Avoid trapping signals that should always terminate (like
KILL
orSTOP
), as they cannot be caught. - Combine
set -e
with ERR traps for robust error handling. - Test your traps thoroughly in different scenarios (manual interrupt, kill signals, SSH disconnection).
- Document which signals your script traps for maintainability.
Key Takeaways
- Bash Signals and Traps let you handle interruptions, exits, and custom events effectively.
- Use
trap
for cleanup, logging, or ignoring signals. - Combine built-in traps like
EXIT
andERR
with user-defined signals for complete control. - Following best practices ensures your scripts are reliable, secure, and production-ready.
FAQ on Bash Signals and Traps
1. What is the purpose of traps in Bash?
Traps allow you to intercept signals and define custom actions, such as cleaning up files, logging, or ignoring interruptions.
2. Can Bash traps handle all signals?
No. Signals like SIGKILL
and SIGSTOP
cannot be trapped or ignored. They are designed to forcefully control processes.
3. What is the difference between EXIT and TERM in Bash?
EXIT
is a Bash-specific trap triggered when the script ends. TERM
is a system signal requesting process termination.
4. How do I ignore a signal in Bash?
You can ignore a signal by setting an empty trap:trap '' QUIT
5. Are Bash Signals and Traps useful in automation?
Yes. They make scripts more robust by handling unexpected events, ensuring safe exits, and maintaining system stability in automation workflows.