Table of Contents
Handle signals in Bash scripts using the trap command. This guide covers common signals like SIGINT, SIGTERM, and provides best practices for handling them.
Introduction to Signal Handling in Bash
In Bash, signals and traps are used to handle interruptions and specific events during the execution of scripts. They provide a way to gracefully manage unexpected or user-initiated interruptions, such as when a user presses Ctrl+C or the system sends a termination signal to your script.
What Are Signals in Bash?
Signals are notifications sent to a process to inform it of an event. They are used to interrupt or terminate a process. For example, pressing Ctrl+C sends the SIGINT signal, which typically terminates a program. Some common signals:
- SIGINT (2): Sent when the user types
Ctrl+C
. It interrupts the process. - SIGTERM (15): Default signal for terminating a process.
- SIGHUP (1): Sent when the terminal disconnects or a session ends.
- SIGKILL (9): Immediately kills the process without cleanup. This signal cannot be caught or ignored.
- SIGQUIT (3): Similar to
SIGINT
, but also generates a core dump file.
Why Use Signal Handling in Bash?
Without signal handling, Bash scripts will terminate unexpectedly when they receive signals like SIGINT or SIGTERM. Signal handling allows scripts to clean up resources, save progress, or gracefully exit when an unexpected event occurs.
Traps
A trap allows you to capture a signal and execute a specific command or function when the signal is received. It’s useful when you want to clean up resources (like temporary files) or perform some actions before the script exits.
trap 'commands' signal_list
commands
: The commands or function to be executed when the signal is received.signal_list
: The signal(s) you want to trap.
Example: Handling SIGINT
(Ctrl+C)
#!/bin/bash
# Trap SIGINT (Ctrl+C)
trap 'echo "Script interrupted by user! Cleaning up..."; exit' SIGINT
echo "This is a long-running script..."
sleep 1000 # Simulate a long-running task
echo "Script finished."
In this script, when the user presses Ctrl+C, instead of immediately terminating, the trap intercepts the SIGINT signal and runs the echo command and exit.
Example: Handling SIGTERM
#!/bin/bash
# Trap SIGTERM (sent when a process is killed)
trap 'echo "Termination signal received. Exiting safely..."; exit 0' SIGTERM
while true; do
echo "Working..."
sleep 10 # Simulating work
done
If this script is sent a SIGTERM signal, it will print a message and then exit gracefully.
Ignoring a Signal
If you don’t want your script to respond to certain signals, you can instruct the trap to ignore them by specifying an empty string as the command.
trap '' SIGINT # Ignore Ctrl+C
Removing a Trap
You can reset the handling of a signal back to the default by specifying – in place of the commands.
trap - SIGINT # Reset handling of SIGINT (Ctrl+C) to default behavior
Trapping EXIT
The special signal EXIT is triggered when the script finishes, regardless of how it ends (whether normally or due to a signal). This can be used for cleanup tasks.
#!/bin/bash
# Trap EXIT
trap 'echo "Cleaning up before exit..."' EXIT
# Simulating script work
echo "Running the script..."
sleep 5
This script will run the cleanup code right before it exits.
Using Functions in Traps
You can also call a function within a trap, making it easier to handle complex tasks.
#!/bin/bash
cleanup() {
echo "Performing cleanup..."
# Add cleanup commands here
}
# Trap SIGINT (Ctrl+C) and SIGTERM (termination signal)
trap cleanup SIGINT SIGTERM
echo "Running script..."
sleep 10
Here, the cleanup function will be called when SIGINT or SIGTERM is received.
Multiple Signals in One Trap
ou can specify multiple signals in a single trap statement.
trap 'echo "Signal caught!"; exit' SIGINT SIGTERM
Common Signals and Their Uses
Signal | Description | Example Usage |
---|---|---|
SIGINT | Interrupt (Ctrl+C) | Gracefully stop a script |
SIGTERM | Termination signal | Cleanly shut down a background process |
SIGHUP | Terminal hang up | Reinitialize a daemon when the terminal closes |
SIGKILL | Kill signal (cannot be caught or ignored) | Immediately kill a process |
Best Practices for Signal Handling in Bash
- Clean Up Resources: Always ensure that open files, background processes, or temporary files are cleaned up before the script exits.
- Log Events: Consider logging signal events for debugging purposes, especially in larger or more complex scripts.
- Use Specific Exit Codes: Exit with specific codes to help identify why the script exited. For example, you could use
exit 130
forSIGINT
andexit 143
forSIGTERM
.
Conclusions
- Signals are used by the system or users to interrupt or stop a process.
- Traps allow you to catch these signals and run specific commands or functions, providing a way to handle unexpected events.
- Useful signals to handle include
SIGINT
,SIGTERM
, andEXIT
. - You can trap multiple signals and use functions for more complex signal handling.
This approach ensures that your Bash scripts handle interruptions gracefully and allows you to clean up resources when necessary.
FAQs:
-
What happens if I don’t handle signals in my Bash script?
If you don’t handle signals, the default action is taken for each signal. For example, SIGINT will terminate the script immediately, and any resources used (such as files or network connections) might not be cleaned up properly.
-
Can I ignore a signal in Bash?
Yes, you can ignore a signal using trap ” SIGNAL. For instance, trap ” SIGINT will ignore Ctrl+C inputs.
-
How can I find out what signals a process can receive?
You can list all signals available on your system by running the kill -l command.
-
Can SIGKILL or SIGSTOP be caught in a Bash script?
No, SIGKILL and SIGSTOP cannot be caught, blocked, or ignored. These are handled directly by the kernel.
-
How can I test signal handling in my script without pressing Ctrl+C?
You can send signals to your script using the kill command. For example, kill -SIGINT sends a SIGINT to the process with the specified PID.