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_SPEC
is 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),cleanup
runs.trap cleanup INT
: Ensurescleanup
runs if interrupted withCtrl+C
before 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
EXIT
for general cleanup. - Optionally trap
INT
andTERM
for 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