Trap Signals: Handle Ctrl+C and Script Exit
Summary: Use trap to handle signals and clean up.
Writing shell scripts often means dealing with unexpected interruptions or ensuring that resources are cleaned up when your script finishes running, whether by success or error. Unix-like systems provide a mechanism for handling these events through signals, and Bash's built-in trap command enables scripts to respond to them in a controlled way. In this post, you'll learn how to handle signals like SIGINT (Ctrl+C) and script exits to protect your scripts and perform proper cleanup.
What Are Signals?
Signals are messages that tell a Unix process to do something—stop, reload configuration, terminate, etc. Common signals include:
- SIGINT (2): Sent when you press
Ctrl+C. Intended to interrupt a running process. - SIGTERM (15): Politely asks a process to terminate.
- SIGHUP (1): Terminal hangup.
- EXIT: Special pseudo-signal in Bash trap, not a real Unix signal, called when the script exits for any reason.
Why Trap Signals?
Without traps, if a script is interrupted, temporary files might be left behind or critical operations interrupted in an unsafe state. Using trap, you can:
- Delete temporary files
- Save logs or information
- Kill child processes
- Reset terminal settings
The trap Command Basics
Syntax:
trap 'commands' SIGNAL_SPEC
'commands'is what to run when the specified signal occurs.SIGNAL_SPECis which signals to respond to.
Example — catching SIGINT:
trap 'echo "Interrupted!"; exit 1' INT
If you press Ctrl+C, you’ll see "Interrupted!" before the script exits.
Handling Script Exit for Cleanup
Suppose your script generates a temporary file and you want to make sure it's deleted no matter what (including if interrupted):
#!/bin/bash
TMPFILE=$(mktemp)
echo "Temporary file: $TMPFILE"
# Define cleanup function
cleanup() {
rm -f "$TMPFILE"
echo "Temporary file deleted."
}
# Trap EXIT and INT (Ctrl+C)
trap cleanup EXIT
trap cleanup INT
# Simulate long-running task
sleep 60
How this works:
trap cleanup EXIT: When the script finishes (success, error, interruption),cleanupruns.trap cleanup INT: Ensurescleanupruns if interrupted withCtrl+Cbefore EXIT.
Tip: trap cleanup EXIT usually suffices because Bash will call this regardless of how the script is exited unless the process is killed with something like kill -9.
Handling Multiple Signals
You can trap multiple signals by listing them:
trap cleanup EXIT INT TERM
This covers normal script exit, Ctrl+C, and termination.
Example: Final Script
Here's a complete pattern:
#!/bin/bash
TMPFILE=$(mktemp)
cleanup() {
echo "Cleaning up..."
rm -f "$TMPFILE"
}
# Trap common signals
trap cleanup EXIT INT TERM
echo "Doing work. PID $$"
# Simulate work
sleep 60
Run the script, press Ctrl+C, or send kill—cleanup will always occur.
Advanced: Ignoring Signals
To ignore a signal, trap it with '' (empty command):
trap '' INT # Now, Ctrl+C won't interrupt the script!
Use with caution. For most scripts, you want to clean up and exit gracefully, not ignore interrupts.
Best Practices
- Clean up all resources (temp files, child processes, mounts) in your trap handler.
- Trap
EXITfor general cleanup. - Optionally trap
INTandTERMfor interruption/termination. - Compose your trap function so it can be safely called multiple times.
- Always quote variables and handle errors in cleanup!
Conclusion
Using trap in bash scripts empowers you to handle interruptions and exits gracefully, ensuring your scripts are robust and don't leave behind unwanted side effects. Next time your script deals with files, resources, or subprocesses, deploy trap for safer scripting!
Further Reading