Bash Trap Command: Complete Guide to Signal Handling

Master Bash trap commands for graceful signal handling, cleanup operations, and error management in shell scripts with practical examples.

Bash Trap Command: Complete Guide to Signal Handling in Scripts

Table of Contents

1. [Introduction to Trap Command](#introduction-to-trap-command) 2. [Basic Syntax and Usage](#basic-syntax-and-usage) 3. [Signal Types and Numbers](#signal-types-and-numbers) 4. [Trap Command Variations](#trap-command-variations) 5. [Practical Examples](#practical-examples) 6. [Best Practices](#best-practices) 7. [Advanced Usage Scenarios](#advanced-usage-scenarios) 8. [Troubleshooting Common Issues](#troubleshooting-common-issues)

Introduction to Trap Command

The trap command in Bash is a powerful built-in utility that allows scripts to handle signals gracefully. Signals are software interrupts that can be sent to running processes to communicate various events or requests. The trap command enables scripts to define custom actions that should be executed when specific signals are received, providing a mechanism for cleanup operations, error handling, and controlled script termination.

When a script runs without trap handlers, receiving certain signals like SIGINT (Ctrl+C) or SIGTERM will cause immediate termination, potentially leaving temporary files, open connections, or incomplete operations. The trap command addresses this limitation by allowing developers to specify exactly what should happen when these signals are received.

Why Use Trap Commands

The primary purposes of using trap commands include:

- Cleanup Operations: Remove temporary files, close database connections, or release system resources - Graceful Shutdown: Ensure processes terminate cleanly rather than abruptly - Error Handling: Execute specific actions when errors occur or scripts exit unexpectedly - State Preservation: Save current work or system state before termination - Logging: Record important information about script execution and termination reasons

Basic Syntax and Usage

The fundamental syntax of the trap command follows this pattern:

`bash trap 'command_list' signal_list `

Syntax Components

| Component | Description | Example | |-----------|-------------|---------| | trap | The command keyword | trap | | 'command_list' | Commands to execute (quoted) | 'echo "Cleaning up"; rm temp.txt' | | signal_list | Space-separated list of signals | SIGINT SIGTERM EXIT |

Basic Command Structure

`bash

Single command for single signal

trap 'echo "Script interrupted"' INT

Multiple commands for single signal

trap 'echo "Cleaning up"; rm -f /tmp/script.$; exit 1' INT

Single command for multiple signals

trap 'cleanup_function' INT TERM EXIT

Function call as trap action

trap cleanup_function INT TERM `

Removing Traps

`bash

Remove trap for specific signal

trap - INT

Remove trap for multiple signals

trap - INT TERM EXIT

Reset to default behavior

trap INT TERM `

Listing Current Traps

`bash

List all current traps

trap

List trap for specific signal

trap -p INT `

Signal Types and Numbers

Understanding different signal types is crucial for effective trap usage. Signals can be specified by name, number, or symbolic name.

Common Signal Reference Table

| Signal Name | Signal Number | Description | Default Action | Trappable | |-------------|---------------|-------------|----------------|-----------| | SIGHUP | 1 | Hangup detected on controlling terminal | Terminate | Yes | | SIGINT | 2 | Interrupt from keyboard (Ctrl+C) | Terminate | Yes | | SIGQUIT | 3 | Quit from keyboard (Ctrl+\) | Core dump | Yes | | SIGKILL | 9 | Kill signal | Terminate | No | | SIGTERM | 15 | Termination signal | Terminate | Yes | | SIGSTOP | 19 | Stop process | Stop | No | | SIGTSTP | 20 | Terminal stop signal (Ctrl+Z) | Stop | Yes | | SIGUSR1 | 10 | User-defined signal 1 | Terminate | Yes | | SIGUSR2 | 12 | User-defined signal 2 | Terminate | Yes |

Special Trap Conditions

| Condition | Description | Usage Example | |-----------|-------------|---------------| | EXIT | Script exit (normal or abnormal) | trap 'echo "Script ending"' EXIT | | ERR | Command returns non-zero exit status | trap 'echo "Error occurred"' ERR | | DEBUG | Before each command execution | trap 'echo "Debug: $BASH_COMMAND"' DEBUG | | RETURN | Shell function or sourced script returns | trap 'echo "Function returned"' RETURN |

Signal Specification Methods

`bash

By signal name (recommended)

trap 'cleanup' SIGINT SIGTERM

By signal name without SIG prefix

trap 'cleanup' INT TERM

By signal number

trap 'cleanup' 2 15

Mixed specification (not recommended but valid)

trap 'cleanup' INT 15 SIGQUIT `

Trap Command Variations

Function-Based Traps

Using functions with traps provides better organization and reusability:

`bash #!/bin/bash

Define cleanup function

cleanup() { echo "Performing cleanup operations..." # Remove temporary files rm -f /tmp/script_temp_$ rm -f /tmp/script_lock_$ # Close file descriptors exec 3>&- exec 4>&- # Kill background processes jobs -p | xargs -r kill echo "Cleanup completed" exit 0 }

Set trap to call function

trap cleanup INT TERM EXIT

Script main logic

echo "Script starting with PID $" touch /tmp/script_temp_$ touch /tmp/script_lock_$

Simulate long-running process

for i in {1..100}; do echo "Processing item $i" sleep 1 done `

Conditional Trap Actions

Traps can include conditional logic to handle different scenarios:

`bash #!/bin/bash

interrupted=false

handle_interrupt() { if [ "$interrupted" = "false" ]; then echo "First interrupt received. Press Ctrl+C again to force quit." interrupted=true return else echo "Second interrupt received. Forcing quit..." cleanup_and_exit fi }

cleanup_and_exit() { echo "Performing emergency cleanup..." # Emergency cleanup code here exit 1 }

trap handle_interrupt INT trap cleanup_and_exit TERM

Reset interrupt flag periodically

while true; do echo "Working..." sleep 5 interrupted=false done `

Nested Trap Handling

Complex scripts may require different trap behaviors in different contexts:

`bash #!/bin/bash

Global cleanup function

global_cleanup() { echo "Global cleanup executing..." rm -f /tmp/global_* }

Database operation cleanup

db_cleanup() { echo "Database cleanup executing..." # Close database connections mysql -e "KILL CONNECTION_ID();" 2>/dev/null || true global_cleanup }

File operation cleanup

file_cleanup() { echo "File cleanup executing..." # Unlock files, remove temporary files rm -f /tmp/file_lock_* global_cleanup }

Set initial trap

trap global_cleanup EXIT INT TERM

Function that changes trap behavior

database_operations() { # Override trap for database operations trap db_cleanup EXIT INT TERM echo "Starting database operations..." # Database work here sleep 10 # Restore original trap trap global_cleanup EXIT INT TERM }

Function that changes trap behavior

file_operations() { # Override trap for file operations trap file_cleanup EXIT INT TERM echo "Starting file operations..." # File work here sleep 10 # Restore original trap trap global_cleanup EXIT INT TERM }

Main script execution

database_operations file_operations `

Practical Examples

Example 1: Basic Cleanup Script

`bash #!/bin/bash

basic_cleanup.sh - Demonstrates basic trap usage

Global variables

TEMP_DIR="/tmp/script_$" LOG_FILE="/var/log/script.log" PID_FILE="/var/run/script.pid"

Cleanup function

cleanup() { echo "$(date): Cleanup initiated" >> "$LOG_FILE" # Remove temporary directory if [ -d "$TEMP_DIR" ]; then rm -rf "$TEMP_DIR" echo "$(date): Removed temporary directory $TEMP_DIR" >> "$LOG_FILE" fi # Remove PID file if [ -f "$PID_FILE" ]; then rm -f "$PID_FILE" echo "$(date): Removed PID file $PID_FILE" >> "$LOG_FILE" fi echo "$(date): Cleanup completed" >> "$LOG_FILE" exit 0 }

Set trap

trap cleanup INT TERM EXIT

Initialize script

echo $ > "$PID_FILE" mkdir -p "$TEMP_DIR" echo "$(date): Script started with PID $" >> "$LOG_FILE"

Main script logic

echo "Script running. Press Ctrl+C to test cleanup..."

Simulate work

for i in {1..60}; do echo "Working... $i/60" touch "$TEMP_DIR/work_file_$i" sleep 1 done

echo "Script completed normally" `

Example 2: Advanced Error Handling

`bash #!/bin/bash

error_handling.sh - Advanced error handling with traps

Enable strict error handling

set -euo pipefail

Global variables

SCRIPT_NAME=$(basename "$0") SCRIPT_PID=$ ERROR_LOG="/var/log/${SCRIPT_NAME}_errors.log" OPERATION_LOG="/var/log/${SCRIPT_NAME}_operations.log"

Error handling function

handle_error() { local exit_code=$? local line_number=$1 local command="$2" echo "$(date): ERROR - Script $SCRIPT_NAME failed" >> "$ERROR_LOG" echo "$(date): Exit Code: $exit_code" >> "$ERROR_LOG" echo "$(date): Line Number: $line_number" >> "$ERROR_LOG" echo "$(date): Failed Command: $command" >> "$ERROR_LOG" echo "$(date): PID: $SCRIPT_PID" >> "$ERROR_LOG" echo "---" >> "$ERROR_LOG" # Perform cleanup cleanup_on_error exit $exit_code }

Cleanup function for errors

cleanup_on_error() { echo "$(date): Emergency cleanup initiated" >> "$OPERATION_LOG" # Kill any background jobs jobs -p | while read pid; do kill -TERM "$pid" 2>/dev/null || true done # Remove lock files rm -f /tmp/script_lock_* echo "$(date): Emergency cleanup completed" >> "$OPERATION_LOG" }

Normal cleanup function

normal_cleanup() { echo "$(date): Normal cleanup initiated" >> "$OPERATION_LOG" # Graceful cleanup operations echo "$(date): Script completed successfully" >> "$OPERATION_LOG" }

Set traps

trap 'handle_error ${LINENO} "$BASH_COMMAND"' ERR trap normal_cleanup EXIT trap cleanup_on_error INT TERM

Main script operations

echo "$(date): Starting operations..." >> "$OPERATION_LOG"

Simulate operations that might fail

risky_operation() { echo "Performing risky operation..." # This might fail if [ $((RANDOM % 3)) -eq 0 ]; then false # Simulate failure fi echo "Risky operation completed successfully" }

Execute operations

for i in {1..5}; do echo "Operation $i starting..." risky_operation echo "Operation $i completed" sleep 1 done `

Example 3: Resource Management Script

`bash #!/bin/bash

resource_manager.sh - Comprehensive resource management

Resource tracking arrays

declare -a TEMP_FILES=() declare -a TEMP_DIRS=() declare -a BACKGROUND_PIDS=() declare -a OPEN_FDS=()

Add resource tracking functions

track_temp_file() { TEMP_FILES+=("$1") }

track_temp_dir() { TEMP_DIRS+=("$1") }

track_background_pid() { BACKGROUND_PIDS+=("$1") }

track_file_descriptor() { OPEN_FDS+=("$1") }

Comprehensive cleanup function

comprehensive_cleanup() { echo "Starting comprehensive cleanup..." # Clean up background processes if [ ${#BACKGROUND_PIDS[@]} -gt 0 ]; then echo "Terminating ${#BACKGROUND_PIDS[@]} background processes..." for pid in "${BACKGROUND_PIDS[@]}"; do if kill -0 "$pid" 2>/dev/null; then echo "Terminating process $pid" kill -TERM "$pid" 2>/dev/null || true sleep 1 kill -KILL "$pid" 2>/dev/null || true fi done fi # Close file descriptors if [ ${#OPEN_FDS[@]} -gt 0 ]; then echo "Closing ${#OPEN_FDS[@]} file descriptors..." for fd in "${OPEN_FDS[@]}"; do eval "exec ${fd}>&-" 2>/dev/null || true done fi # Remove temporary files if [ ${#TEMP_FILES[@]} -gt 0 ]; then echo "Removing ${#TEMP_FILES[@]} temporary files..." for file in "${TEMP_FILES[@]}"; do rm -f "$file" 2>/dev/null || true done fi # Remove temporary directories if [ ${#TEMP_DIRS[@]} -gt 0 ]; then echo "Removing ${#TEMP_DIRS[@]} temporary directories..." for dir in "${TEMP_DIRS[@]}"; do rm -rf "$dir" 2>/dev/null || true done fi echo "Comprehensive cleanup completed" }

Set trap

trap comprehensive_cleanup EXIT INT TERM

Example usage of resource tracking

echo "Creating resources..."

Create and track temporary files

temp_file1=$(mktemp) temp_file2=$(mktemp) track_temp_file "$temp_file1" track_temp_file "$temp_file2"

Create and track temporary directories

temp_dir1=$(mktemp -d) temp_dir2=$(mktemp -d) track_temp_dir "$temp_dir1" track_temp_dir "$temp_dir2"

Start and track background processes

sleep 30 & track_background_pid $!

sleep 60 & track_background_pid $!

Open and track file descriptors

exec 3> "$temp_file1" exec 4> "$temp_file2" track_file_descriptor 3 track_file_descriptor 4

Simulate script work

echo "Script working with resources..." echo "Data1" >&3 echo "Data2" >&4

Create some files in temp directories

touch "$temp_dir1/test1.txt" touch "$temp_dir2/test2.txt"

echo "Resources created. Script will clean up on exit." sleep 10

echo "Script work completed" `

Best Practices

Design Principles

| Principle | Description | Implementation | |-----------|-------------|----------------| | Idempotency | Cleanup should be safe to run multiple times | Check resource existence before cleanup | | Reliability | Cleanup should not fail even if resources are missing | Use conditional checks and error suppression | | Completeness | All created resources should be tracked and cleaned | Maintain resource lists or use systematic naming | | Speed | Cleanup should be fast to avoid delays | Prioritize critical cleanup operations |

Trap Implementation Guidelines

`bash

Good: Use functions for complex cleanup

cleanup() { # Organized cleanup logic cleanup_files cleanup_processes cleanup_network } trap cleanup EXIT INT TERM

Avoid: Inline complex logic

trap 'rm -f file1; kill $pid1; rm -f file2; kill $pid2; ...' EXIT

`

`bash

Good: Check resource existence

cleanup() { if [ -f "$LOCK_FILE" ]; then rm -f "$LOCK_FILE" fi if [ -n "$BACKGROUND_PID" ] && kill -0 "$BACKGROUND_PID" 2>/dev/null; then kill "$BACKGROUND_PID" fi }

Avoid: Assuming resources exist

cleanup() {

rm "$LOCK_FILE" # May fail if file doesn't exist

kill "$BACKGROUND_PID" # May fail if process doesn't exist

}

`

Error Handling in Traps

`bash

Robust trap function with error handling

cleanup() { local exit_code=$? # Disable further traps to prevent recursion trap - EXIT INT TERM # Perform cleanup with error suppression { rm -rf "$TEMP_DIR" kill -TERM "$BACKGROUND_PID" rm -f "$LOCK_FILE" } 2>/dev/null || true # Log cleanup completion echo "Cleanup completed with original exit code: $exit_code" >&2 # Exit with original code exit $exit_code } `

Signal Priority Handling

`bash

Handle different signals with appropriate responses

handle_sigterm() { echo "SIGTERM received - graceful shutdown" graceful_shutdown }

handle_sigint() { echo "SIGINT received - user interruption" user_interruption_cleanup }

handle_sigquit() { echo "SIGQUIT received - immediate termination" emergency_cleanup }

trap handle_sigterm TERM trap handle_sigint INT trap handle_sigquit QUIT `

Advanced Usage Scenarios

Scenario 1: Database Connection Management

`bash #!/bin/bash

db_connection_manager.sh

Database configuration

DB_HOST="localhost" DB_USER="app_user" DB_NAME="application_db" CONNECTION_ID=""

Establish database connection

establish_db_connection() { echo "Establishing database connection..." # Get connection ID for cleanup CONNECTION_ID=$(mysql -h "$DB_HOST" -u "$DB_USER" -D "$DB_NAME" \ -e "SELECT CONNECTION_ID();" -s -N 2>/dev/null) if [ -n "$CONNECTION_ID" ]; then echo "Database connected with ID: $CONNECTION_ID" return 0 else echo "Failed to establish database connection" return 1 fi }

Database cleanup function

cleanup_database() { if [ -n "$CONNECTION_ID" ]; then echo "Closing database connection ID: $CONNECTION_ID" # Rollback any pending transactions mysql -h "$DB_HOST" -u "$DB_USER" -D "$DB_NAME" \ -e "ROLLBACK;" 2>/dev/null || true # Close the connection mysql -h "$DB_HOST" -u "$DB_USER" -D "$DB_NAME" \ -e "KILL $CONNECTION_ID;" 2>/dev/null || true echo "Database connection closed" fi }

Set trap for database cleanup

trap cleanup_database EXIT INT TERM

Main database operations

if establish_db_connection; then echo "Performing database operations..." # Begin transaction mysql -h "$DB_HOST" -u "$DB_USER" -D "$DB_NAME" -e "BEGIN;" # Simulate database work for i in {1..10}; do echo "Database operation $i" mysql -h "$DB_HOST" -u "$DB_USER" -D "$DB_NAME" \ -e "INSERT INTO activity_log (message) VALUES ('Operation $i');" sleep 1 done # Commit transaction mysql -h "$DB_HOST" -u "$DB_USER" -D "$DB_NAME" -e "COMMIT;" echo "Database operations completed successfully" else echo "Cannot proceed without database connection" exit 1 fi `

Scenario 2: Multi-Process Coordination

`bash #!/bin/bash

multi_process_coordinator.sh

Process tracking

declare -a WORKER_PIDS=() COORDINATOR_PID=$ SHARED_MEMORY="/tmp/coordinator_$"

Initialize shared resources

initialize_shared_resources() { mkdir -p "$SHARED_MEMORY" echo "0" > "$SHARED_MEMORY/completed_tasks" echo "active" > "$SHARED_MEMORY/status" }

Worker process function

worker_process() { local worker_id=$1 local tasks=$2 echo "Worker $worker_id starting with $tasks tasks" for ((i=1; i<=tasks; i++)); do # Simulate work sleep $((RANDOM % 3 + 1)) # Update shared counter atomically ( flock -x 200 local completed=$(cat "$SHARED_MEMORY/completed_tasks") echo $((completed + 1)) > "$SHARED_MEMORY/completed_tasks" ) 200>"$SHARED_MEMORY/lock" echo "Worker $worker_id completed task $i" done echo "Worker $worker_id finished" }

Cleanup function for coordinator

cleanup_coordinator() { echo "Coordinator cleanup initiated" # Signal all workers to stop echo "stopping" > "$SHARED_MEMORY/status" # Terminate worker processes for pid in "${WORKER_PIDS[@]}"; do if kill -0 "$pid" 2>/dev/null; then echo "Terminating worker process $pid" kill -TERM "$pid" 2>/dev/null || true fi done # Wait for workers to terminate gracefully local timeout=10 while [ $timeout -gt 0 ] && [ ${#WORKER_PIDS[@]} -gt 0 ]; do local remaining_pids=() for pid in "${WORKER_PIDS[@]}"; do if kill -0 "$pid" 2>/dev/null; then remaining_pids+=("$pid") fi done WORKER_PIDS=("${remaining_pids[@]}") if [ ${#WORKER_PIDS[@]} -eq 0 ]; then break fi sleep 1 ((timeout--)) done # Force kill any remaining workers for pid in "${WORKER_PIDS[@]}"; do kill -KILL "$pid" 2>/dev/null || true done # Clean up shared resources rm -rf "$SHARED_MEMORY" echo "Coordinator cleanup completed" }

Set trap for coordinator

trap cleanup_coordinator EXIT INT TERM

Initialize

initialize_shared_resources

Start worker processes

echo "Starting worker processes..." for worker_id in {1..5}; do worker_process "$worker_id" 10 & WORKER_PIDS+=($!) echo "Started worker $worker_id with PID ${WORKER_PIDS[-1]}" done

Monitor progress

echo "Monitoring worker progress..." total_expected=$((5 * 10)) # 5 workers, 10 tasks each

while true; do if [ ! -f "$SHARED_MEMORY/completed_tasks" ]; then break fi completed=$(cat "$SHARED_MEMORY/completed_tasks" 2>/dev/null || echo "0") echo "Progress: $completed/$total_expected tasks completed" # Check if all workers are done active_workers=0 for pid in "${WORKER_PIDS[@]}"; do if kill -0 "$pid" 2>/dev/null; then ((active_workers++)) fi done if [ $active_workers -eq 0 ]; then echo "All workers completed" break fi sleep 2 done

echo "Coordination completed successfully" `

Scenario 3: Network Service Management

`bash #!/bin/bash

network_service_manager.sh

Service configuration

SERVICE_PORT=8080 SERVICE_PID="" LOG_FILE="/var/log/service_manager.log"

Start network service

start_service() { echo "$(date): Starting network service on port $SERVICE_PORT" >> "$LOG_FILE" # Start a simple HTTP server (example) python3 -m http.server "$SERVICE_PORT" & SERVICE_PID=$! # Wait for service to be ready local retries=10 while [ $retries -gt 0 ]; do if netstat -ln | grep -q ":$SERVICE_PORT "; then echo "$(date): Service started successfully with PID $SERVICE_PID" >> "$LOG_FILE" return 0 fi sleep 1 ((retries--)) done echo "$(date): Failed to start service" >> "$LOG_FILE" return 1 }

Stop network service

stop_service() { if [ -n "$SERVICE_PID" ] && kill -0 "$SERVICE_PID" 2>/dev/null; then echo "$(date): Stopping service with PID $SERVICE_PID" >> "$LOG_FILE" # Graceful shutdown kill -TERM "$SERVICE_PID" 2>/dev/null || true # Wait for graceful shutdown local timeout=30 while [ $timeout -gt 0 ] && kill -0 "$SERVICE_PID" 2>/dev/null; do sleep 1 ((timeout--)) done # Force kill if necessary if kill -0 "$SERVICE_PID" 2>/dev/null; then echo "$(date): Force killing service" >> "$LOG_FILE" kill -KILL "$SERVICE_PID" 2>/dev/null || true fi echo "$(date): Service stopped" >> "$LOG_FILE" fi }

Cleanup network resources

cleanup_network() { echo "$(date): Network cleanup initiated" >> "$LOG_FILE" # Stop the service stop_service # Clean up any remaining connections on the port local connections=$(netstat -an | grep ":$SERVICE_PORT " | wc -l) if [ "$connections" -gt 0 ]; then echo "$(date): Found $connections remaining connections" >> "$LOG_FILE" # Additional cleanup if needed fi # Remove any socket files rm -f "/tmp/service_socket_$" echo "$(date): Network cleanup completed" >> "$LOG_FILE" }

Signal handlers

handle_reload() { echo "$(date): Reload signal received" >> "$LOG_FILE" stop_service sleep 2 start_service }

handle_shutdown() { echo "$(date): Shutdown signal received" >> "$LOG_FILE" cleanup_network exit 0 }

Set traps

trap cleanup_network EXIT trap handle_shutdown INT TERM trap handle_reload HUP

Main execution

echo "$(date): Service manager starting" >> "$LOG_FILE"

if start_service; then echo "Service is running. Send SIGHUP to reload, SIGTERM/SIGINT to stop." # Keep the script running while kill -0 "$SERVICE_PID" 2>/dev/null; do sleep 5 done echo "$(date): Service process ended unexpectedly" >> "$LOG_FILE" else echo "$(date): Failed to start service" >> "$LOG_FILE" exit 1 fi `

Troubleshooting Common Issues

Issue 1: Trap Not Executing

Problem: Trap commands are not being executed when signals are received.

Common Causes and Solutions:

| Cause | Solution | Example | |-------|----------|---------| | Incorrect signal name | Use correct signal names | trap 'cleanup' INT not trap 'cleanup' SIGINT2 | | Trap set after signal received | Set traps early in script | Move trap commands to top of script | | Script exits before trap setup | Add trap immediately after shebang | See example below |

`bash #!/bin/bash

Correct: Set trap early

trap 'echo "Cleanup"; exit' INT TERM

Wrong: Setting trap after potential exit points

some_command_that_might_fail

trap 'echo "Cleanup"; exit' INT TERM

`

Issue 2: Infinite Loops in Trap Functions

Problem: Trap function calls itself or triggers the same signal repeatedly.

`bash

Problematic code

cleanup() { echo "Cleaning up..." exit 1 # This triggers EXIT trap again } trap cleanup EXIT INT

Solution: Disable trap before exit

cleanup() { trap - EXIT INT # Disable traps first echo "Cleaning up..." exit 1 } trap cleanup EXIT INT `

Issue 3: Resource Cleanup Failures

Problem: Cleanup operations fail, leaving resources in inconsistent state.

`bash

Robust cleanup with error handling

cleanup() { local exit_code=$? # Disable trap to prevent recursion trap - EXIT INT TERM # Cleanup with error suppression and logging { # File cleanup if [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ]; then rm -rf "$TEMP_DIR" || echo "Warning: Failed to remove $TEMP_DIR" >&2 fi # Process cleanup if [ -n "$BACKGROUND_PID" ]; then kill -TERM "$BACKGROUND_PID" 2>/dev/null || true sleep 1 kill -KILL "$BACKGROUND_PID" 2>/dev/null || true fi # Network cleanup if [ -n "$SERVICE_PORT" ]; then fuser -k "$SERVICE_PORT/tcp" 2>/dev/null || true fi } || { echo "Some cleanup operations failed" >&2 } exit $exit_code } `

Issue 4: Debugging Trap Execution

Problem: Difficulty determining if and when traps are being executed.

`bash

Debug-enabled trap function

debug_cleanup() { local exit_code=$? local signal=${1:-"unknown"} echo "DEBUG: Trap executed - Signal: $signal, Exit Code: $exit_code, PID: $" >&2 echo "DEBUG: Call stack:" >&2 # Print call stack local frame=0 while caller $frame >&2; do ((frame++)) done # Actual cleanup perform_cleanup exit $exit_code }

Set debug traps

trap 'debug_cleanup EXIT' EXIT trap 'debug_cleanup INT' INT trap 'debug_cleanup TERM' TERM `

Testing Trap Functionality

`bash #!/bin/bash

trap_test.sh - Test script for trap functionality

test_cleanup() { echo "Test cleanup executed at $(date)" echo "Process ID: $" echo "Exit code: $?" # Verify cleanup actions if [ -f "/tmp/test_file_$" ]; then rm -f "/tmp/test_file_$" echo "Test file removed successfully" fi }

Set trap

trap test_cleanup EXIT INT TERM

Create test resources

touch "/tmp/test_file_$" echo "Test file created: /tmp/test_file_$"

Test scenarios

echo "Testing trap functionality..." echo "1. Normal exit - let script complete" echo "2. Interrupt - press Ctrl+C" echo "3. Terminate - send SIGTERM from another terminal: kill -TERM $"

Wait for testing

sleep 30

echo "Script completed normally" `

This comprehensive guide covers the essential aspects of using the trap command in Bash scripts for effective signal handling and resource management. The examples and best practices provided should enable robust script development with proper cleanup and error handling mechanisms.

Tags

  • Linux
  • bash
  • shell-scripting
  • signal-handling
  • system-administration

Related Articles

Popular Technical Articles & Tutorials

Explore our comprehensive collection of technical articles, programming tutorials, and IT guides written by industry experts:

Browse all 8+ technical articles | Read our IT blog

Bash Trap Command: Complete Guide to Signal Handling