Bash exit codes provide essential feedback about command execution success or failure, enabling robust error handling and automation. This comprehensive guide covers exit code fundamentals, advanced error handling patterns, debugging techniques, and enterprise-grade script reliability practices.

Understanding Bash Exit Codes

Exit Code Fundamentals

What Are Exit Codes?

Exit codes (also called return codes or exit status) are integer values returned by commands and scripts to indicate their execution status:

  • 0: Success - Command completed without errors
  • 1-255: Failure - Various error conditions
  • Non-zero: General indication of failure or specific error type

Basic Exit Code Checking

# Run a command and check its exit code
/etc/init.d/dnsmasq start
echo "Exit code: $?"

# Alternative using command substitution
service_status=$(systemctl start nginx; echo $?)
echo "Service start result: $service_status"

# Check exit code immediately in conditional
if /bin/true; then
    echo "Command succeeded (exit code 0)"
else
    echo "Command failed (non-zero exit code)"
fi

Standard Exit Codes and Meanings

Common Exit Code Ranges

# Standard exit codes
0    # Success
1    # General errors
2    # Misuse of shell builtins
126  # Command invoked cannot execute
127  # Command not found
128  # Invalid argument to exit
130  # Script terminated by Control-C (128 + 2)
255  # Exit status out of range

System-Specific Exit Codes

#!/bin/bash
# Display common system exit codes

declare -A exit_codes=(
    [0]="Success"
    [1]="General errors"
    [2]="Misuse of shell builtins"
    [64]="Command line usage error"
    [65]="Data format error"
    [66]="Cannot open input"
    [67]="Addressee unknown"
    [68]="Host name unknown"
    [69]="Service unavailable"
    [70]="Internal software error"
    [71]="System error"
    [72]="Critical OS file missing"
    [73]="Can't create output file"
    [74]="Input/output error"
    [75]="Temp failure; user is invited to retry"
    [76]="Remote error in protocol"
    [77]="Permission denied"
    [78]="Configuration error"
    [126]="Command invoked cannot execute"
    [127]="Command not found"
    [128]="Invalid argument to exit"
    [130]="Script terminated by Control-C"
)

# Function to explain exit code
explain_exit_code() {
    local code=$1
    if [[ -n ${exit_codes[$code]} ]]; then
        echo "Exit code $code: ${exit_codes[$code]}"
    else
        echo "Exit code $code: Unknown or application-specific"
    fi
}

# Example usage
explain_exit_code 0
explain_exit_code 127
explain_exit_code 130

Advanced Exit Code Handling

Immediate Exit Code Capture

Multiple Methods to Capture Exit Codes

#!/bin/bash
# Different ways to capture and handle exit codes

# Method 1: Direct capture
command_to_run
exit_code=$?
echo "Method 1 - Exit code: $exit_code"

# Method 2: Inline capture with command substitution
exit_code=$(command_to_run > /dev/null 2>&1; echo $?)
echo "Method 2 - Exit code: $exit_code"

# Method 3: Pipeline exit codes (requires pipefail)
set -o pipefail
echo "test" | grep "nonexistent" | wc -l
pipeline_exit=${PIPESTATUS[1]}  # Exit code of grep command
echo "Method 3 - Pipeline exit code: $pipeline_exit"

# Method 4: Function with return value
check_service() {
    systemctl is-active "$1" >/dev/null 2>&1
    return $?
}

check_service "nginx"
echo "Method 4 - Function exit code: $?"

Advanced Exit Code Variables

#!/bin/bash
# Understanding special exit code variables

# PIPESTATUS array - exit codes of pipeline commands
echo "hello world" | grep "world" | wc -l
echo "Pipeline exit codes: ${PIPESTATUS[@]}"
echo "First command (echo): ${PIPESTATUS[0]}"
echo "Second command (grep): ${PIPESTATUS[1]}"
echo "Third command (wc): ${PIPESTATUS[2]}"

# Last background process exit code
sleep 1 &
background_pid=$!
wait $background_pid
echo "Background process exit code: $?"

# Exit code of last command in function
test_function() {
    ls /nonexistent/directory 2>/dev/null
    local func_exit=$?
    echo "Function internal exit code: $func_exit"
    return $func_exit
}

test_function
echo "Function return code: $?"

Error Handling Patterns

Basic Error Handling with Conditionals

#!/bin/bash
# Simple error handling patterns

# Pattern 1: If-then-else
if command_that_might_fail; then
    echo "Command succeeded"
else
    echo "Command failed with exit code: $?"
    exit 1
fi

# Pattern 2: Short-circuit evaluation
command_that_might_fail && echo "Success" || echo "Failed"

# Pattern 3: Early exit on failure
command_that_might_fail || {
    echo "Command failed, exiting..."
    exit 1
}

# Pattern 4: Continue on failure with logging
if ! command_that_might_fail; then
    echo "Warning: Command failed, but continuing..."
fi

Advanced Error Handling Functions

#!/bin/bash
# Advanced error handling with functions

# Global error handling configuration
set -euo pipefail  # Exit on error, undefined vars, pipe failures

# Error logging function
log_error() {
    local exit_code=$1
    local line_number=$2
    local command="$3"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    echo "[$timestamp] ERROR: Command '$command' failed with exit code $exit_code at line $line_number" >&2
    
    # Optional: Send to syslog
    logger -t "script-error" "Command '$command' failed with exit code $exit_code at line $line_number"
}

# Trap function for automatic error handling
error_trap() {
    local exit_code=$?
    local line_number=$1
    local command="$BASH_COMMAND"
    
    log_error $exit_code $line_number "$command"
    
    # Cleanup function call
    cleanup_on_error
    
    exit $exit_code
}

# Cleanup function
cleanup_on_error() {
    echo "Performing cleanup..."
    # Remove temporary files
    rm -f /tmp/script-temp-*
    # Kill background processes
    jobs -p | xargs -r kill
    # Restore original configurations
    # ... cleanup code here ...
}

# Set error trap
trap 'error_trap $LINENO' ERR

# Safe command execution function
safe_execute() {
    local command="$1"
    local description="$2"
    local max_retries=${3:-1}
    local retry_delay=${4:-1}
    
    for ((i=1; i<=max_retries; i++)); do
        echo "Executing: $description (attempt $i/$max_retries)"
        
        if eval "$command"; then
            echo "✓ Success: $description"
            return 0
        else
            local exit_code=$?
            echo "✗ Failed: $description (exit code: $exit_code)"
            
            if [[ $i -lt $max_retries ]]; then
                echo "Retrying in $retry_delay seconds..."
                sleep $retry_delay
            else
                echo "All retry attempts failed"
                return $exit_code
            fi
        fi
    done
}

# Usage examples
safe_execute "systemctl start nginx" "Starting Nginx service" 3 5
safe_execute "wget -q --spider https://example.com" "Checking website connectivity" 2 3

Script Reliability and Debugging

Bash Script Options for Reliability

Essential Script Headers

#!/bin/bash
# Comprehensive script reliability settings

# Exit immediately on any command failure
set -e

# Exit on undefined variable usage
set -u

# Fail on any command in pipeline
set -o pipefail

# Enable debug mode (optional)
# set -x

# Alternative: Combined settings
# set -euo pipefail

# Function to disable strict mode temporarily
disable_strict_mode() {
    set +euo pipefail
}

# Function to re-enable strict mode
enable_strict_mode() {
    set -euo pipefail
}

# Example of temporary relaxed error handling
disable_strict_mode
optional_command_that_might_fail || true
enable_strict_mode

Debug and Verbose Modes

#!/bin/bash
# Script debugging and verbose output

# Parse command line arguments for debug mode
DEBUG=false
VERBOSE=false

while [[ $# -gt 0 ]]; do
    case $1 in
        -d|--debug)
            DEBUG=true
            set -x  # Enable debug mode
            shift
            ;;
        -v|--verbose)
            VERBOSE=true
            shift
            ;;
        *)
            echo "Unknown option: $1"
            exit 1
            ;;
    esac
done

# Debug logging function
debug_log() {
    if [[ "$DEBUG" == true ]]; then
        echo "[DEBUG $(date '+%H:%M:%S')] $*" >&2
    fi
}

# Verbose logging function
verbose_log() {
    if [[ "$VERBOSE" == true ]]; then
        echo "[INFO $(date '+%H:%M:%S')] $*"
    fi
}

# Command execution with logging
execute_with_logging() {
    local command="$1"
    local description="$2"
    
    verbose_log "Executing: $description"
    debug_log "Command: $command"
    
    if eval "$command"; then
        verbose_log "Success: $description"
        debug_log "Exit code: 0"
        return 0
    else
        local exit_code=$?
        echo "Error: $description failed with exit code $exit_code" >&2
        debug_log "Failed command: $command"
        return $exit_code
    fi
}

# Usage examples
execute_with_logging "ls -la /tmp" "Listing temporary directory"
execute_with_logging "ping -c 1 google.com" "Testing internet connectivity"

Comprehensive Error Handling Framework

Enterprise-Grade Error Handler

#!/bin/bash
# Enterprise error handling framework

# Configuration
readonly SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly LOG_DIR="/var/log/scripts"
readonly LOG_FILE="$LOG_DIR/${SCRIPT_NAME%.*}.log"
readonly ERROR_LOG="$LOG_DIR/${SCRIPT_NAME%.*}-error.log"
readonly LOCK_FILE="/var/run/${SCRIPT_NAME%.*}.lock"

# Ensure log directory exists
mkdir -p "$LOG_DIR"

# Logging functions
log() {
    local level="$1"
    shift
    local message="$*"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
    
    if [[ "$level" == "ERROR" ]]; then
        echo "[$timestamp] [$level] $message" >> "$ERROR_LOG"
    fi
}

log_info() { log "INFO" "$@"; }
log_warn() { log "WARN" "$@"; }
log_error() { log "ERROR" "$@"; }
log_debug() { log "DEBUG" "$@"; }

# Enhanced error trap function
enhanced_error_trap() {
    local exit_code=$?
    local line_number=$1
    local command="$BASH_COMMAND"
    local function_name="${FUNCNAME[1]:-main}"
    
    log_error "Command failed in function '$function_name' at line $line_number"
    log_error "Command: $command"
    log_error "Exit code: $exit_code"
    
    # Stack trace
    log_error "Call stack:"
    for ((i=1; i<${#FUNCNAME[@]}; i++)); do
        log_error "  $i: ${FUNCNAME[i]} (${BASH_SOURCE[i]}:${BASH_LINENO[i-1]})"
    done
    
    # Cleanup
    cleanup_resources
    
    # Send notification (if configured)
    send_error_notification "$exit_code" "$line_number" "$command"
    
    exit $exit_code
}

# Cleanup function
cleanup_resources() {
    log_info "Performing cleanup..."
    
    # Remove lock file
    [[ -f "$LOCK_FILE" ]] && rm -f "$LOCK_FILE"
    
    # Kill background jobs
    local jobs_pids=$(jobs -p)
    if [[ -n "$jobs_pids" ]]; then
        log_info "Terminating background jobs: $jobs_pids"
        echo "$jobs_pids" | xargs -r kill -TERM
        sleep 2
        echo "$jobs_pids" | xargs -r kill -KILL 2>/dev/null || true
    fi
    
    # Remove temporary files
    find /tmp -name "${SCRIPT_NAME%.*}-*" -type f -mmin +60 -delete 2>/dev/null || true
    
    log_info "Cleanup completed"
}

# Error notification function
send_error_notification() {
    local exit_code="$1"
    local line_number="$2"
    local command="$3"
    
    # Email notification (if mail is configured)
    if command -v mail >/dev/null 2>&1 && [[ -n "${ADMIN_EMAIL:-}" ]]; then
        {
            echo "Script: $SCRIPT_NAME"
            echo "Host: $(hostname)"
            echo "Time: $(date)"
            echo "Exit Code: $exit_code"
            echo "Line: $line_number"
            echo "Command: $command"
            echo ""
            echo "Last 10 log entries:"
            tail -10 "$LOG_FILE"
        } | mail -s "Script Error: $SCRIPT_NAME on $(hostname)" "$ADMIN_EMAIL"
    fi
    
    # Slack notification (if webhook is configured)
    if [[ -n "${SLACK_WEBHOOK:-}" ]]; then
        local payload=$(cat <<EOF
{
    "text": "Script Error Alert",
    "attachments": [
        {
            "color": "danger",
            "fields": [
                {"title": "Script", "value": "$SCRIPT_NAME", "short": true},
                {"title": "Host", "value": "$(hostname)", "short": true},
                {"title": "Exit Code", "value": "$exit_code", "short": true},
                {"title": "Line", "value": "$line_number", "short": true},
                {"title": "Command", "value": "$command", "short": false}
            ]
        }
    ]
}
EOF
        )
        curl -X POST -H 'Content-type: application/json' \
             --data "$payload" "$SLACK_WEBHOOK" >/dev/null 2>&1 || true
    fi
}

# Set error handling
set -euo pipefail
trap 'enhanced_error_trap $LINENO' ERR
trap cleanup_resources EXIT

# Lock file management
create_lock() {
    if [[ -f "$LOCK_FILE" ]]; then
        local lock_pid=$(cat "$LOCK_FILE" 2>/dev/null || echo "")
        if [[ -n "$lock_pid" ]] && kill -0 "$lock_pid" 2>/dev/null; then
            log_error "Script is already running (PID: $lock_pid)"
            exit 1
        else
            log_warn "Removing stale lock file"
            rm -f "$LOCK_FILE"
        fi
    fi
    
    echo $$ > "$LOCK_FILE"
    log_info "Lock file created: $LOCK_FILE"
}

# Robust command execution with retries
execute_with_retry() {
    local command="$1"
    local description="$2"
    local max_attempts="${3:-3}"
    local retry_delay="${4:-5}"
    local timeout="${5:-30}"
    
    local attempt=1
    
    while [[ $attempt -le $max_attempts ]]; do
        log_info "Executing: $description (attempt $attempt/$max_attempts)"
        
        if timeout "$timeout" bash -c "$command"; then
            log_info "Success: $description"
            return 0
        else
            local exit_code=$?
            log_warn "Attempt $attempt failed: $description (exit code: $exit_code)"
            
            if [[ $attempt -lt $max_attempts ]]; then
                log_info "Waiting $retry_delay seconds before retry..."
                sleep "$retry_delay"
                ((attempt++))
            else
                log_error "All attempts failed: $description"
                return $exit_code
            fi
        fi
    done
}

# Conditional execution based on exit codes
execute_if_success() {
    local check_command="$1"
    local exec_command="$2"
    local description="$3"
    
    if eval "$check_command" >/dev/null 2>&1; then
        log_info "Condition met, executing: $description"
        eval "$exec_command"
    else
        log_info "Condition not met, skipping: $description"
    fi
}

# Main script initialization
main() {
    log_info "Starting $SCRIPT_NAME"
    log_info "PID: $$"
    log_info "User: $(whoami)"
    log_info "Working directory: $(pwd)"
    
    # Create lock file
    create_lock
    
    # Example usage of the framework
    execute_with_retry "ping -c 1 google.com" "Testing internet connectivity" 3 2 10
    execute_if_success "systemctl is-active nginx" "systemctl reload nginx" "Reloading Nginx if active"
    
    log_info "$SCRIPT_NAME completed successfully"
}

# Run main function
main "$@"

Practical Applications and Examples

Service Management Scripts

Robust Service Controller

#!/bin/bash
# Robust service management with exit code handling

# Service management functions
service_start() {
    local service_name="$1"
    local max_wait="${2:-30}"
    
    echo "Starting service: $service_name"
    
    if systemctl start "$service_name"; then
        echo "✓ Service start command issued successfully"
        
        # Wait for service to become active
        local wait_time=0
        while [[ $wait_time -lt $max_wait ]]; do
            if systemctl is-active "$service_name" >/dev/null 2>&1; then
                echo "✓ Service $service_name is now active"
                return 0
            fi
            
            sleep 1
            ((wait_time++))
            echo -n "."
        done
        
        echo "✗ Service $service_name failed to become active within $max_wait seconds"
        return 1
    else
        local exit_code=$?
        echo "✗ Failed to start service $service_name (exit code: $exit_code)"
        return $exit_code
    fi
}

service_stop() {
    local service_name="$1"
    local max_wait="${2:-30}"
    
    echo "Stopping service: $service_name"
    
    if systemctl stop "$service_name"; then
        echo "✓ Service stop command issued successfully"
        
        # Wait for service to become inactive
        local wait_time=0
        while [[ $wait_time -lt $max_wait ]]; do
            if ! systemctl is-active "$service_name" >/dev/null 2>&1; then
                echo "✓ Service $service_name is now inactive"
                return 0
            fi
            
            sleep 1
            ((wait_time++))
            echo -n "."
        done
        
        echo "✗ Service $service_name failed to stop within $max_wait seconds"
        return 1
    else
        local exit_code=$?
        echo "✗ Failed to stop service $service_name (exit code: $exit_code)"
        return $exit_code
    fi
}

service_restart() {
    local service_name="$1"
    local stop_wait="${2:-30}"
    local start_wait="${3:-30}"
    
    echo "Restarting service: $service_name"
    
    # Stop service first
    if service_stop "$service_name" "$stop_wait"; then
        # Start service
        if service_start "$service_name" "$start_wait"; then
            echo "✓ Service $service_name restarted successfully"
            return 0
        else
            echo "✗ Failed to start service $service_name after stop"
            return 1
        fi
    else
        echo "✗ Failed to stop service $service_name for restart"
        return 1
    fi
}

# Health check function
service_health_check() {
    local service_name="$1"
    local port="${2:-}"
    local url="${3:-}"
    
    echo "Performing health check for: $service_name"
    
    # Check if service is active
    if ! systemctl is-active "$service_name" >/dev/null 2>&1; then
        echo "✗ Service $service_name is not active"
        return 1
    fi
    
    # Check port if specified
    if [[ -n "$port" ]]; then
        if ! netstat -tuln | grep -q ":$port "; then
            echo "✗ Service $service_name is not listening on port $port"
            return 2
        fi
        echo "✓ Service $service_name is listening on port $port"
    fi
    
    # Check URL if specified
    if [[ -n "$url" ]]; then
        if ! curl -sf "$url" >/dev/null 2>&1; then
            echo "✗ Service $service_name health check failed for URL: $url"
            return 3
        fi
        echo "✓ Service $service_name health check passed for URL: $url"
    fi
    
    echo "✓ All health checks passed for service: $service_name"
    return 0
}

# Example usage
main() {
    local services=("nginx" "mysql" "redis-server")
    local failed_services=()
    
    for service in "${services[@]}"; do
        if ! service_restart "$service"; then
            failed_services+=("$service")
        fi
    done
    
    # Report results
    if [[ ${#failed_services[@]} -eq 0 ]]; then
        echo "✓ All services restarted successfully"
        exit 0
    else
        echo "✗ Failed to restart services: ${failed_services[*]}"
        exit 1
    fi
}

# Run if script is executed directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi

File Operations with Error Handling

Robust File Processing

#!/bin/bash
# File operations with comprehensive error handling

# File validation function
validate_file() {
    local file_path="$1"
    local required_permissions="${2:-r}"
    
    # Check if file exists
    if [[ ! -e "$file_path" ]]; then
        echo "Error: File does not exist: $file_path" >&2
        return 1
    fi
    
    # Check if it's a regular file
    if [[ ! -f "$file_path" ]]; then
        echo "Error: Not a regular file: $file_path" >&2
        return 2
    fi
    
    # Check permissions
    case "$required_permissions" in
        "r"|"read")
            if [[ ! -r "$file_path" ]]; then
                echo "Error: File not readable: $file_path" >&2
                return 3
            fi
            ;;
        "w"|"write")
            if [[ ! -w "$file_path" ]]; then
                echo "Error: File not writable: $file_path" >&2
                return 4
            fi
            ;;
        "x"|"execute")
            if [[ ! -x "$file_path" ]]; then
                echo "Error: File not executable: $file_path" >&2
                return 5
            fi
            ;;
        "rw"|"read-write")
            if [[ ! -r "$file_path" ]] || [[ ! -w "$file_path" ]]; then
                echo "Error: File not readable/writable: $file_path" >&2
                return 6
            fi
            ;;
    esac
    
    return 0
}

# Safe file copy with verification
safe_copy() {
    local source="$1"
    local destination="$2"
    local verify_checksum="${3:-true}"
    
    echo "Copying: $source -> $destination"
    
    # Validate source file
    if ! validate_file "$source" "read"; then
        return 1
    fi
    
    # Create destination directory if needed
    local dest_dir=$(dirname "$destination")
    if [[ ! -d "$dest_dir" ]]; then
        if ! mkdir -p "$dest_dir"; then
            echo "Error: Failed to create destination directory: $dest_dir" >&2
            return 2
        fi
    fi
    
    # Get source file size and checksum
    local source_size=$(stat -f%z "$source" 2>/dev/null || stat -c%s "$source" 2>/dev/null)
    local source_checksum=""
    if [[ "$verify_checksum" == "true" ]]; then
        source_checksum=$(sha256sum "$source" | cut -d' ' -f1)
    fi
    
    # Perform copy
    if ! cp "$source" "$destination"; then
        local exit_code=$?
        echo "Error: Copy operation failed (exit code: $exit_code)" >&2
        return $exit_code
    fi
    
    # Verify copy
    local dest_size=$(stat -f%z "$destination" 2>/dev/null || stat -c%s "$destination" 2>/dev/null)
    if [[ "$source_size" != "$dest_size" ]]; then
        echo "Error: Size mismatch - Source: $source_size, Destination: $dest_size" >&2
        rm -f "$destination"  # Clean up failed copy
        return 3
    fi
    
    # Verify checksum if requested
    if [[ "$verify_checksum" == "true" ]]; then
        local dest_checksum=$(sha256sum "$destination" | cut -d' ' -f1)
        if [[ "$source_checksum" != "$dest_checksum" ]]; then
            echo "Error: Checksum mismatch" >&2
            echo "Source: $source_checksum" >&2
            echo "Destination: $dest_checksum" >&2
            rm -f "$destination"  # Clean up failed copy
            return 4
        fi
    fi
    
    echo "✓ Copy completed and verified successfully"
    return 0
}

# Batch file processing with error reporting
process_files() {
    local source_dir="$1"
    local destination_dir="$2"
    local file_pattern="${3:-*}"
    
    local processed_count=0
    local failed_count=0
    local failed_files=()
    
    echo "Processing files from $source_dir to $destination_dir"
    echo "Pattern: $file_pattern"
    
    # Find and process files
    while IFS= read -r -d '' file; do
        local filename=$(basename "$file")
        local dest_file="$destination_dir/$filename"
        
        echo "Processing: $filename"
        
        if safe_copy "$file" "$dest_file"; then
            ((processed_count++))
            echo "✓ Processed: $filename"
        else
            ((failed_count++))
            failed_files+=("$filename")
            echo "✗ Failed: $filename"
        fi
    done < <(find "$source_dir" -name "$file_pattern" -type f -print0)
    
    # Report results
    echo ""
    echo "Processing complete:"
    echo "  Successfully processed: $processed_count files"
    echo "  Failed: $failed_count files"
    
    if [[ $failed_count -gt 0 ]]; then
        echo "  Failed files: ${failed_files[*]}"
        return 1
    fi
    
    return 0
}

Network Operations with Exit Code Handling

Network Connectivity Testing

#!/bin/bash
# Network connectivity testing with detailed exit codes

# DNS resolution test
test_dns_resolution() {
    local hostname="$1"
    local dns_server="${2:-8.8.8.8}"
    
    echo "Testing DNS resolution for: $hostname"
    
    if nslookup "$hostname" "$dns_server" >/dev/null 2>&1; then
        echo "✓ DNS resolution successful"
        return 0
    else
        local exit_code=$?
        echo "✗ DNS resolution failed (exit code: $exit_code)"
        return $exit_code
    fi
}

# Network connectivity test
test_network_connectivity() {
    local target="$1"
    local port="${2:-80}"
    local timeout="${3:-10}"
    
    echo "Testing connectivity to: $target:$port"
    
    if timeout "$timeout" bash -c "echo >/dev/tcp/$target/$port" 2>/dev/null; then
        echo "✓ Network connectivity successful"
        return 0
    else
        local exit_code=$?
        echo "✗ Network connectivity failed (exit code: $exit_code)"
        
        # Try to determine the specific reason
        if ! ping -c 1 -W 5 "$target" >/dev/null 2>&1; then
            echo "  → Host unreachable"
            return 1
        elif ! nc -z -w 5 "$target" "$port" 2>/dev/null; then
            echo "  → Port $port closed or filtered"
            return 2
        else
            echo "  → Unknown connectivity issue"
            return $exit_code
        fi
    fi
}

# HTTP/HTTPS test with detailed response codes
test_http_endpoint() {
    local url="$1"
    local expected_code="${2:-200}"
    local timeout="${3:-30}"
    local max_redirects="${4:-5}"
    
    echo "Testing HTTP endpoint: $url"
    
    local response
    response=$(curl -s -w "%{http_code}|%{time_total}|%{redirect_count}" \
                   --max-time "$timeout" \
                   --max-redirs "$max_redirects" \
                   -o /dev/null \
                   "$url" 2>/dev/null)
    
    local curl_exit=$?
    
    if [[ $curl_exit -eq 0 ]]; then
        local http_code=$(echo "$response" | cut -d'|' -f1)
        local time_total=$(echo "$response" | cut -d'|' -f2)
        local redirect_count=$(echo "$response" | cut -d'|' -f3)
        
        echo "  HTTP Status: $http_code"
        echo "  Response Time: ${time_total}s"
        echo "  Redirects: $redirect_count"
        
        if [[ "$http_code" == "$expected_code" ]]; then
            echo "✓ HTTP endpoint test successful"
            return 0
        else
            echo "✗ Unexpected HTTP status code (expected: $expected_code, got: $http_code)"
            return 10
        fi
    else
        echo "✗ HTTP request failed (curl exit code: $curl_exit)"
        
        # Decode curl exit codes
        case $curl_exit in
            6) echo "  → Couldn't resolve host" ;;
            7) echo "  → Failed to connect to host" ;;
            28) echo "  → Operation timeout" ;;
            35) echo "  → SSL connect error" ;;
            *) echo "  → Curl error code: $curl_exit" ;;
        esac
        
        return $curl_exit
    fi
}

# Comprehensive network health check
network_health_check() {
    local targets=("google.com" "github.com" "stackoverflow.com")
    local failed_tests=0
    local total_tests=0
    
    echo "Starting comprehensive network health check..."
    echo "================================================"
    
    for target in "${targets[@]}"; do
        echo ""
        echo "Testing target: $target"
        echo "------------------------"
        
        # DNS test
        ((total_tests++))
        if ! test_dns_resolution "$target"; then
            ((failed_tests++))
            continue
        fi
        
        # Ping test
        ((total_tests++))
        if ! test_network_connectivity "$target" 80; then
            ((failed_tests++))
            continue
        fi
        
        # HTTP test
        ((total_tests++))
        if ! test_http_endpoint "https://$target"; then
            ((failed_tests++))
        fi
    done
    
    echo ""
    echo "Network Health Check Summary"
    echo "============================="
    echo "Total tests: $total_tests"
    echo "Passed: $((total_tests - failed_tests))"
    echo "Failed: $failed_tests"
    
    if [[ $failed_tests -eq 0 ]]; then
        echo "✓ All network tests passed"
        return 0
    else
        echo "✗ $failed_tests network tests failed"
        return 1
    fi
}

# Run network health check if script is executed directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    network_health_check
fi

This comprehensive Bash exit codes and error handling guide provides enterprise-grade techniques for building robust, reliable shell scripts with proper error detection, handling, and reporting capabilities.