SyntaxStudy
Sign Up
Linux / Bash Bash Functions, Error Handling, and Best Practices
Linux / Bash Beginner 1 min read

Bash Functions, Error Handling, and Best Practices

Functions in Bash allow you to encapsulate reusable blocks of logic with their own positional parameters and local variable scope. They improve readability and maintainability of scripts. A well-structured script will define functions first and call them at the bottom, often through a `main` function that orchestrates the overall flow. Robust error handling is the difference between a script that works in the happy path and one that is production-ready. The `set -e` option causes the script to exit on any unhandled error. `set -u` treats unset variables as errors. `set -o pipefail` makes a pipeline fail if any stage fails (not just the last). Together, `set -euo pipefail` is the recommended preamble for reliable scripts. Traps allow you to run cleanup code when a script exits or receives a signal. The `trap` command registers a handler for signals or the pseudo-signal `EXIT`. This ensures temporary files are cleaned up and locks are released even when the script exits unexpectedly. Input validation, informative error messages, and logging to a file with timestamps complete the picture of a production-quality Bash script.
Example
#!/bin/bash
set -euo pipefail

# ---- Logging helper ----
LOG_FILE="/var/log/deploy.log"

log() {
    local level="$1"
    local message="$2"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message" | tee -a "$LOG_FILE"
}

# ---- Cleanup trap ----
TMPDIR=$(mktemp -d)

cleanup() {
    log "INFO" "Cleaning up temporary files in $TMPDIR"
    rm -rf "$TMPDIR"
}
trap cleanup EXIT
trap 'log "ERROR" "Script interrupted"; exit 1' INT TERM

# ---- Input validation function ----
validate_args() {
    if [[ $# -lt 2 ]]; then
        log "ERROR" "Usage: $0 <environment> <version>"
        exit 1
    fi
    local env="$1"
    if [[ ! "$env" =~ ^(staging|production)$ ]]; then
        log "ERROR" "Environment must be 'staging' or 'production'"
        exit 1
    fi
}

# ---- Retry function ----
retry() {
    local attempts="$1"
    shift
    local cmd=("$@")
    local i
    for (( i=1; i<=attempts; i++ )); do
        if "${cmd[@]}"; then
            return 0
        fi
        log "WARN" "Attempt $i/$attempts failed. Retrying..."
        sleep 2
    done
    log "ERROR" "Command failed after $attempts attempts: ${cmd[*]}"
    return 1
}

# ---- Main function ----
main() {
    validate_args "$@"
    local ENV="$1"
    local VERSION="$2"

    log "INFO" "Starting deployment of version $VERSION to $ENV"
    retry 3 curl -sf "https://api.example.com/health"
    log "INFO" "Deployment complete"
}

main "$@"