Bash Signals and Traps: Handling Script Interruptions Gracefully

Bash, the powerful command-line interface for Linux and Unix systems, gives you fine-grained control over how your scripts respond to signals. Signals are software interrupts that can be triggered by various events, such as pressing Ctrl+C or encountering an error. Let’s explore how Bash’s trap command can help you handle these interruptions with elegance.

Understanding Signals

Signals are like messages sent to your script, indicating that something noteworthy has happened. Common signals include:

  • INT (Interrupt): Triggered by Ctrl+C, typically used to stop a running process.
  • QUIT (Quit): Triggered by Ctrl+\ (backslash), often used for a more forceful termination.
  • TERM (Terminate): A generic signal to request a process to stop.
  • HUP (Hangup): Sent when a controlling terminal is closed.

The trap Command: Your Signal Handler

Bash’s trap command lets you specify what your script should do when it receives a specific signal. The syntax is:

trap 'commands' signal [signal ...]
  • commands: The commands to execute when the signal is received.
  • signal: The name of the signal to trap (e.g., INT, QUIT, TERM).

Example: Gracefully Handling Ctrl+C

#!/bin/bash

cleanup() {
    echo "Cleaning up..."
    # Perform cleanup tasks (remove temp files, etc.)
}

trap cleanup INT  # Trap the INT signal (Ctrl+C)

# Your script's main tasks...

Here’s the output: If the user interrupts the script using Ctrl+C, the output will be:

Cleaning up...

Example: Custom Signal Handling

#!/bin/bash

custom_handler() {
    echo "Received a custom signal (USR1)"
}

trap custom_handler USR1  # Trap a user-defined signal (USR1)

# Your script's main tasks...

To send the USR1 signal to a script with the process ID (PID) 12345, you would use the following command:

kill -USR1 12345

Example: Ignoring Signals

trap '' QUIT  # Ignore the QUIT signal (Ctrl+\)

Advanced Traps: Nested and Dynamic

You can even set traps within trap handlers, allowing for dynamic adjustments to signal handling behavior.

#!/bin/bash
count=1

trap 'echo "First trap activated!"; count=$((count+1)); trap "echo trapped $count times" QUIT' QUIT

echo "This script will ignore first QUIT signal, then print a message for subsequent QUIT signals"

while true; do
  sleep 1
done

Explanation: The script counts how many times the QUIT signal has been sent. It ignores the first QUIT signal, then prints a message for each subsequent one.

Why Use Traps?

  • Clean Exit: Ensure your script cleans up temporary files, releases resources, or saves state before termination.
  • Custom Actions: Respond to signals with specific actions (e.g., logging, notifications).
  • Robustness: Make your scripts more resilient to unexpected interruptions.