Bash Signals Traps
A signal is a short message that the system sends to a running program. Pressing Ctrl+C sends one. A trap lets a script catch a signal and run cleanup code before it stops. Traps protect temporary files and half-finished work.
A Doorbell Analogy
A doorbell rings and the person inside decides what to do: open the door, ignore the sound, or finish a task first. A signal acts like the bell, and a trap holds the plan for the person inside.
Keyboard Ctrl+C kill command System shutdown
| | |
+-----------+-----------+----------------------+
|
v
+-----------+
| SIGNAL |
+-----+-----+
|
+---------+----------+
| |
v v
No trap set trap defined
Script stops Cleanup code runs
Common Signals
| Signal | Number | Trigger |
|---|---|---|
| SIGINT | 2 | Ctrl+C from the keyboard |
| SIGTERM | 15 | Polite request to stop (default for kill) |
| SIGHUP | 1 | Terminal window closes |
| SIGKILL | 9 | Forced stop, cannot be caught |
| SIGSTOP | 19 | Pause the program, cannot be caught |
| EXIT | none | Bash special event: the script ends for any reason |
Run trap -l to see the complete list on your system.
Basic Trap Syntax
trap 'commands' SIGNALQuotation marks wrap the commands. A function name works inside the quotes as well.
Catch Ctrl+C
#!/bin/bash
trap 'echo " Interrupt caught. Stopping safely."; exit 1' SIGINT
echo "Working... press Ctrl+C to stop"
while true
do
sleep 1
doneOutput after pressing Ctrl+C:
Working... press Ctrl+C to stop
^C Interrupt caught. Stopping safely.Clean Up Temporary Files With EXIT
The EXIT trap runs when the script finishes normally, fails, or gets interrupted. It makes the best place for cleanup.
#!/bin/bash
temp_file=$(mktemp)
cleanup() {
rm -f "$temp_file"
echo "Temporary file removed"
}
trap cleanup EXIT
echo "Writing data to $temp_file"
echo "sample data" > "$temp_file"
cat "$temp_file"Output:
Writing data to /tmp/tmp.k3J9xQ2aBd
sample data
Temporary file removedThe cleanup function runs even if the script crashes halfway.
Handle Several Signals
#!/bin/bash
handle_stop() {
echo "Received stop request. Saving progress..."
exit 0
}
trap handle_stop SIGINT SIGTERM
echo "Process ID: $$"
while true
do
sleep 2
doneThe variable $$ holds the process ID of the script. Open a second terminal and run kill PID with that number to send SIGTERM and watch the handler run.
Ignore a Signal
An empty command string makes the script ignore the signal:
trap '' SIGINT
echo "Ctrl+C is disabled for 5 seconds"
sleep 5
trap - SIGINT
echo "Ctrl+C works again"The dash form trap - SIGINT restores the default behavior.
Trap Errors With ERR
The ERR event fires when a command fails:
#!/bin/bash
trap 'echo "Problem on line $LINENO"' ERR
echo "Step one"
ls /missing_folder
echo "Step two"Output:
Step one
ls: cannot access '/missing_folder': No such file or directory
Problem on line 5
Step twoThe variable $LINENO reports the line number of the failed command. Add set -e at the top to stop the script after the first failure.
Send Signals With kill
kill -SIGTERM 4521 # polite stop
kill -SIGINT 4521 # same as Ctrl+C
kill -9 4521 # forced stop, no cleanup runsTry SIGTERM first. The forced signal skips every trap, so temporary files stay behind.
Practical Example: Lock File Guard
A lock file prevents two copies of a script from running at once. A trap removes the lock when the script ends.
#!/bin/bash
lock="/tmp/myjob.lock"
if [ -e "$lock" ]; then
echo "Another copy is running"
exit 1
fi
touch "$lock"
trap 'rm -f "$lock"' EXIT
echo "Job started"
sleep 10
echo "Job finished"Key Takeaways
- A signal is a message sent to a running program.
trap 'commands' SIGNALdefines what happens when the signal arrives.- The
EXITtrap suits cleanup work. - SIGKILL and SIGSTOP cannot be caught.
- Use
trap - SIGNALto restore default behavior.
