Strict_mode
Chapter 32: Strict Mode in Bash
Section titled “Chapter 32: Strict Mode in Bash”Overview
Section titled “Overview”Strict mode is a collection of bash options that make scripts more robust, reliable, and easier to debug. This chapter covers the recommended settings for production-quality bash scripts.
What is Strict Mode?
Section titled “What is Strict Mode?”Strict mode is a set of bash options that:
- Exit on errors (
set -e) - Exit on undefined variables (
set -u) - Pipeline fails on command failure (
set -o pipefail)
┌────────────────────────────────────────────────────────────────┐│ Strict Mode Benefits │├────────────────────────────────────────────────────────────────┤│ ││ 1. Fail Fast - Errors caught immediately ││ 2. No Silent Failures - Unset variables cause errors ││ 3. Pipeline Errors - All pipeline commands must succeed ││ 4. Easier Debugging - Clear error locations ││ 5. More Predictable - No unexpected behavior ││ │└────────────────────────────────────────────────────────────────┘The Three Pillars
Section titled “The Three Pillars”1. set -e (errexit)
Section titled “1. set -e (errexit)”# Exit immediately if command exits with non-zero status
#!/bin/bashset -e
# This will cause script to exitfalseecho "This never runs"
# Unless handledfalse || trueecho "This runs because of || true"2. set -u (nounset)
Section titled “2. set -u (nounset)”# Exit when trying to use undefined variables
#!/bin/bashset -u
echo "$undefined_var" # Error!
# Unless handledecho "${undefined_var:-default}" # Uses default3. set -o pipefail
Section titled “3. set -o pipefail”# Pipeline returns the exit status of the rightmost command
#!/bin/bashset -euo pipefail
# Without pipefail: succeeds (last command)# With pipefail: fails (first command fails)false | trueecho "This runs without pipefail"Combined Usage
Section titled “Combined Usage”The Recommended Header
Section titled “The Recommended Header”#!/usr/bin/env bash# Strict modeset -euo pipefailVariations
Section titled “Variations”# Basic strict modeset -euo pipefail
# Short formset -Eeuo pipefail
# With xtrace for debuggingset -euxo pipefailHandling Strict Mode Issues
Section titled “Handling Strict Mode Issues”Handling set -e
Section titled “Handling set -e”#!/bin/bashset -euo pipefail
# Using ||command_that_might_fail || trueecho "Continues after potential failure"
# Using conditionalif command_that_might_fail; then echo "Success"fiecho "Continues either way"
# Using if blocksif ! command_that_might_fail; then echo "Command failed, but we handled it"fiHandling set -u
Section titled “Handling set -u”#!/bin/bashset -euo pipefail
# Using default valuesecho "${UNDEFINED_VAR:-default_value}"
# Using parameter expansion: "${VAR:=value}" # Sets default if not set
# Using conditionalif [[ -n "${VAR:-}" ]]; then echo "VAR is set: $VAR"fi
# Checking if setif [[ -v VAR ]]; then echo "VAR is set"fiBest Practices
Section titled “Best Practices”Always Use Strict Mode
Section titled “Always Use Strict Mode”#!/usr/bin/env bash# Put at the top of every script
set -euo pipefailDefine Variables Early
Section titled “Define Variables Early”#!/bin/bashset -euo pipefail
# Initialize variablesVALUE=""COUNT=0Use Defaults for External Input
Section titled “Use Defaults for External Input”#!/bin/bashset -euo pipefail
# Environment variablesDATABASE_URL="${DATABASE_URL:-postgresql://localhost/db}"
# Function argumentsprocess_file() { local file="${1:-default.txt}" # ...}Real-World Examples
Section titled “Real-World Examples”Database Connection Script
Section titled “Database Connection Script”#!/usr/bin/env bash# Database backup with strict mode
set -euo pipefail
DATABASE_URL="${DATABASE_URL:-postgresql://localhost/appdb}"BACKUP_DIR="${BACKUP_DIR:-/backups}"
log() { echo "[$(date)] $*"; }
main() { local timestamp timestamp=$(date +%Y%m%d_%H%M%S)
log "Starting backup"
local backup_file="${BACKUP_DIR}/db_${timestamp}.sql.gz"
# Check if backup directory exists mkdir -p "$BACKUP_DIR"
# Run backup if ! pg_dump "$DATABASE_URL" | gzip > "$backup_file"; then log "Backup failed!" return 1 fi
# Verify backup if [[ ! -s "$backup_file" ]]; then log "Backup file is empty!" return 1 fi
log "Backup completed: $backup_file"}
main "$@"API Client Script
Section titled “API Client Script”#!/usr/bin/env bash# API client with strict mode
set -euo pipefail
API_URL="${API_URL:-https://api.example.com}"API_KEY="${API_KEY:-}"
log() { echo "[$(date)] $*"; }error() { echo "[$(date)] ERROR: $*" >&2; exit 1; }
# Check required variables: "${API_KEY:?API_KEY environment variable is required}"
fetch_data() { local endpoint="$1" local response
response=$(curl -s -H "Authorization: Bearer $API_KEY" \ "${API_URL}/${endpoint}")
if [[ -z "$response" ]]; then error "Empty response from API" fi
echo "$response"}
# Example usagedata=$(fetch_data "users")echo "$data"Common Pitfalls
Section titled “Common Pitfalls”Pipelines in Strict Mode
Section titled “Pipelines in Strict Mode”# Problem: grep returns 1 when no match# This fails in strict mode!set -euo pipefail
result=$(grep "pattern" file.txt) # Fails if no match
# Fix: handle the caseset -euo pipefailresult=$(grep "pattern" file.txt || echo "not found")Command Substitution
Section titled “Command Substitution”# Problem: command substitution changes $?set -euo pipefail
# This might fail unexpectedlyoutput=$(command_that_can_fail)# $? is now about command_substitution, not the command
# Fix: check status explicitlycommand_that_can_fail || exit 1output=$(command_that_can_fail)Arrays in Strict Mode
Section titled “Arrays in Strict Mode”# Problem: empty arraysset -euo pipefail
arr=()echo "${arr[0]}" # Error!
# Fix: check length firstarr=()if [[ ${#arr[@]} -gt 0 ]]; then echo "${arr[0]}"fiDebugging Strict Mode Issues
Section titled “Debugging Strict Mode Issues”Temporarily Disable
Section titled “Temporarily Disable”#!/bin/bashset -euo pipefail
# Disable for specific sectionset +ecommand_that_might_failset -e
# Orcommand_that_might_fail || trueDebug with Logging
Section titled “Debug with Logging”#!/bin/bashset -euo pipefail
# Add logging before failing sectionsset -xcommand_that_might_failset +xAdvanced: Custom Strict Mode
Section titled “Advanced: Custom Strict Mode”Define Strict Function
Section titled “Define Strict Function”#!/bin/bash
strict_mode() { set -euo pipefail}
# Use in subshell( strict_mode # This subshell is in strict mode)
# Original shell unchangedLocal Strict Mode in Functions
Section titled “Local Strict Mode in Functions”#!/bin/bash
my_function() { local set -u # This function doesn't require -u
set -e # This function requires -e
# Function code}Summary
Section titled “Summary”In this chapter, you learned:
- ✅ What strict mode is
- ✅ set -e (errexit)
- ✅ set -u (nounset)
- ✅ set -o pipefail
- ✅ Combined usage
- ✅ Handling strict mode issues
- ✅ Best practices
- ✅ Real-world examples
- ✅ Common pitfalls
- ✅ Debugging tips
Next Steps
Section titled “Next Steps”Continue to the next chapter to learn about Best Practices.
Previous Chapter: Debugging Techniques Next Chapter: Best Practices