Error Handling with Trap

ShellBeginner
Practice Now

Introduction

When a script runs, it often creates temporary files or starts background processes. If the user interrupts the script (for example, by pressing Ctrl+C), these temporary files are often left behind, cluttering the system.

To prevent this, scripts need a way to detect when they are being stopped and perform necessary cleanup actions.

In Linux, we use the trap command to catch interruption signals and exit events. Signals are one of the operating system's ways of talking to processes. For example, pressing Ctrl+C usually sends SIGINT, asking the process to stop.

This allows us to define an "on exit" procedure so the script can clean up after itself before terminating.

In this lab, you will:

  1. Create a script that generates temporary files.
  2. Interrupt the script to see the leftovers.
  3. Implement a trap to automatically delete temporary files upon exit.

Create a Long-Running Process

First, let's create a script that simulates a long-running task. It will create a temporary file and then sleep indefinitely.

Long-running scripts are common in administration work. They may watch a log, wait for input, poll a service, or process jobs over time. The longer a script runs, the more important cleanup becomes when something interrupts it.

Create and open long_process.sh in the project directory:

cd ~/project
nano long_process.sh

Type this code:

#!/bin/bash

## Create a temporary file
touch temp_data.txt
echo "Temporary file 'temp_data.txt' created."

## Fall asleep (Simulate a long job)
echo "Process is running. Press Ctrl+C to stop..."
while true; do
  sleep 1
done

Save (Ctrl+O, Enter) and Exit (Ctrl+X).

Make it executable:

chmod +x long_process.sh

The Issue: If you run this script and then stop it with Ctrl+C, the file temp_data.txt will remain on your disk. This is considered bad practice because repeated runs could fill up disk space with garbage files.

Temporary files are a classic example, but the same problem can happen with lock files, sockets, mount points, or background helper processes. Cleanup is really about leaving the system in a predictable state.

Define a Cleanup Function

To handle cleanup properly, it is best practice to define a specific function that contains all the cleanup logic.

Putting cleanup in a separate function keeps the script organized. It also means the same cleanup logic can be reused from different exit paths instead of being copied into multiple places.

Open the script again:

nano long_process.sh

Add the cleanup function at the top of the script:

#!/bin/bash

## Define the cleanup function
cleanup() {
  echo ""
  echo "Cleaning up temporary files..."
  rm -f temp_data.txt
  echo "Cleanup complete."
}

## Create a temporary file
touch temp_data.txt
echo "Temporary file 'temp_data.txt' created."

## Simulate a long-running process
echo "Process is running. Press Ctrl+C to stop..."
while true; do
  sleep 1
done

Save and Exit.

At this stage, we have defined the function, but we haven't told the script when to call it.

Set a Trap to Catch Signals

Now we use the trap command to tell Bash: "If you receive an Interruption Signal (like Ctrl+C), run the cleanup function."

This is one of the clearest examples of a shell script reacting to operating-system events, not just to text input. A signal is an asynchronous message from the system or user to a process, and trap gives your script a chance to respond deliberately.

Open the script:

nano long_process.sh

Add the trap command below the function definition but before the main logic starts.

#!/bin/bash

cleanup() {
  echo ""
  echo "Cleaning up temporary files..."
  rm -f temp_data.txt
  echo "Cleanup complete."
  exit
}

## Register the trap
## SIGINT = Ctrl+C
## EXIT = Any exit (success or failure)
trap cleanup SIGINT EXIT

## The rest of the script...
touch temp_data.txt
echo "Temporary file 'temp_data.txt' created."

echo "Process is running. Press Ctrl+C to stop..."
while true; do
  sleep 1
done

Understanding trap arguments:

  • cleanup: The command or function to run.
  • SIGINT: The signal sent when you press Ctrl+C.
  • EXIT: A pseudo-signal that triggers whenever the script exits for any reason.

Using both SIGINT and EXIT makes the cleanup more reliable. SIGINT covers the common keyboard interruption, while EXIT provides a more general safety net for normal termination and many failure cases.

Save and Exit.

Verify the Cleanup

Now let's verify that our mechanism works.

Run the script:

./long_process.sh

The script will create temp_data.txt and start running.

Now, interrupt it by pressing Ctrl+C.

You should see the output:

^C
Cleaning up temporary files...
Cleanup complete.

Finally, check if the file is gone:

ls temp_data.txt

It should return an error like:

ls: cannot access 'temp_data.txt': No such file or directory

The trap command successfully intercepted the stop signal and executed your cleanup code before the script terminated.

This is a professional scripting habit: if a script creates temporary state, it should also define how that state gets removed. trap is one of the main tools Bash provides for that job.

Summary

In this lab, you learned how to write robust scripts using Trap.

  1. Signals: Understanding that Ctrl+C sends a SIGINT signal to the process.
  2. Trap: Using trap to catch signals and execute specific code.
  3. Cleanup: Automating housekeeping tasks to keep your system clean.

Professional scripts always handle exit scenarios to prevent data corruption and leftover files.