Case
Chapter 8: Case Statements
Section titled “Chapter 8: Case Statements”Overview
Section titled “Overview”The case statement in bash provides a way to compare a value against multiple patterns and execute different code blocks based on which pattern matches. It’s particularly useful for menu-driven scripts, argument parsing, and handling multiple conditions. This chapter covers the syntax, patterns, and practical applications for DevOps workflows.
Basic Syntax
Section titled “Basic Syntax”Simple Case Statement
Section titled “Simple Case Statement”#!/usr/bin/env bash# Case statement syntaxcase variable in pattern1) # commands for pattern1 ;; pattern2) # commands for pattern2 ;; *) # default case ;;esacComplete Example
Section titled “Complete Example”#!/usr/bin/env bashread -p "Enter a day name: " day
case "$day" in Monday) echo "First day of work" ;; Tuesday|Wednesday|Thursday) echo "Mid-week day" ;; Friday) echo "Friday! Almost weekend" ;; Saturday|Sunday) echo "Weekend!" ;; *) echo "Invalid day" ;;esacPattern Matching
Section titled “Pattern Matching”Multiple Patterns
Section titled “Multiple Patterns”#!/usr/bin/env bash# Multiple patterns with |case "$1" in start|Start|START) echo "Starting..." ;; stop|Stop|STOP) echo "Stopping..." ;; restart) echo "Restarting..." ;; *) echo "Unknown command" exit 1 ;;esacWildcard Patterns
Section titled “Wildcard Patterns”#!/usr/bin/env bashfilename="document.pdf"
case "$filename" in *.txt) echo "Text file" ;; *.pdf) echo "PDF file" ;; *.jpg|*.png|*.gif) echo "Image file" ;; *.sh) echo "Shell script" ;; *) echo "Unknown file type" ;;esacCharacter Classes
Section titled “Character Classes”#!/usr/bin/env bashread -p "Enter a character: " char
case "$char" in [a-z]) echo "Lowercase letter" ;; [A-Z]) echo "Uppercase letter" ;; [0-9]) echo "Digit" ;; *) echo "Other character" ;;esacArgument Parsing with Case
Section titled “Argument Parsing with Case”Command-Line Options
Section titled “Command-Line Options”#!/usr/bin/env bash# Initialize default valuesVERBOSE=falseFORCE=falseOUTPUT_FILE=""
# Parse command line argumentswhile [ $# -gt 0 ]; do case "$1" in -h|--help) echo "Usage: $0 [OPTIONS]" echo "Options:" echo " -h, --help Show this help message" echo " -v, --verbose Enable verbose output" echo " -f, --force Force operation" echo " -o, --output Specify output file" exit 0 ;; -v|--verbose) VERBOSE=true shift ;; -f|--force) FORCE=true shift ;; -o|--output) OUTPUT_FILE="$2" shift 2 ;; -*) echo "Unknown option: $1" exit 1 ;; *) # Positional argument echo "Processing file: $1" shift ;; esacdone
echo "Verbose: $VERBOSE"echo "Force: $FORCE"echo "Output: $OUTPUT_FILE"Environment Selection
Section titled “Environment Selection”#!/usr/bin/env bash# Set defaults based on environmentcase "${ENVIRONMENT:-development}" in production) readonly DB_HOST="prod-db.example.com" readonly DB_PORT="5432" readonly LOG_LEVEL="warn" readonly MAX_CONNECTIONS=200 readonly DEBUG=false ;; staging) readonly DB_HOST="staging-db.example.com" readonly DB_PORT="5432" readonly LOG_LEVEL="debug" readonly MAX_CONNECTIONS=50 readonly DEBUG=true ;; development|dev) readonly DB_HOST="localhost" readonly DB_PORT="5432" readonly LOG_LEVEL="debug" readonly MAX_CONNECTIONS=10 readonly DEBUG=true ;; *) echo "Invalid environment: $ENVIRONMENT" echo "Valid environments: production, staging, development" exit 1 ;;esac
echo "Environment: ${ENVIRONMENT:-development}"echo "Database: $DB_HOST:$DB_PORT"echo "Log Level: $LOG_LEVEL"echo "Debug: $DEBUG"Menu Systems
Section titled “Menu Systems”Simple Menu
Section titled “Simple Menu”#!/usr/bin/env bashecho "================================"echo " Server Management Menu"echo "================================"echo "1. Check server status"echo "2. Start service"echo "3. Stop service"echo "4. View logs"echo "5. Backup data"echo "6. Exit"echo "================================"read -p "Enter your choice: " choice
case "$choice" in 1) echo "Checking server status..." systemctl status nginx ;; 2) echo "Starting service..." sudo systemctl start nginx ;; 3) echo "Stopping service..." sudo systemctl stop nginx ;; 4) echo "Viewing logs..." sudo journalctl -u nginx -n 50 ;; 5) echo "Backing up data..." tar -czf backup_$(date +%Y%m%d).tar.gz /var/www ;; 6) echo "Goodbye!" exit 0 ;; *) echo "Invalid choice" exit 1 ;;esacInteractive Menu with Loop
Section titled “Interactive Menu with Loop”#!/usr/bin/env bashshow_menu() { clear echo "================================" echo " Docker Management" echo "================================" echo "1. List containers" echo "2. List images" echo "3. Start container" echo "4. Stop container" echo "5. Remove container" echo "6. View logs" echo "7. Shell into container" echo "0. Exit" echo "================================"}
while true; do show_menu read -p "Enter choice: " choice
case "$choice" in 1) echo "Containers:" docker ps -a ;; 2) echo "Images:" docker images ;; 3) read -p "Container name: " container docker start "$container" ;; 4) read -p "Container name: " container docker stop "$container" ;; 5) read -p "Container name: " container docker rm "$container" ;; 6) read -p "Container name: " container docker logs -f "$container" ;; 7) read -p "Container name: " container docker exec -it "$container" /bin/bash ;; 0) echo "Goodbye!" exit 0 ;; *) echo "Invalid choice" ;; esac
read -p "Press Enter to continue..."doneService Management
Section titled “Service Management”Generic Service Controller
Section titled “Generic Service Controller”#!/usr/bin/env bashset -euo pipefail
# Check if service name providedif [ $# -lt 2 ]; then echo "Usage: $0 <action> <service>" echo "Actions: start, stop, restart, status, enable, disable" exit 1fi
ACTION="$1"SERVICE="$2"
case "$ACTION" in start) echo "Starting $SERVICE..." sudo systemctl start "$SERVICE" echo "$SERVICE started" ;; stop) echo "Stopping $SERVICE..." sudo systemctl stop "$SERVICE" echo "$SERVICE stopped" ;; restart) echo "Restarting $SERVICE..." sudo systemctl restart "$SERVICE" echo "$SERVICE restarted" ;; status) systemctl status "$SERVICE" ;; enable) echo "Enabling $SERVICE..." sudo systemctl enable "$SERVICE" echo "$SERVICE enabled" ;; disable) echo "Disabling $SERVICE..." sudo systemctl disable "$SERVICE" echo "$SERVICE disabled" ;; *) echo "Unknown action: $ACTION" exit 1 ;;esacFile Type Detection
Section titled “File Type Detection”Advanced File Detection
Section titled “Advanced File Detection”#!/usr/bin/env bashdetect_file_type() { local file="$1"
if [ ! -e "$file" ]; then echo "File does not exist" return 1 fi
case "$(file -b --mime-type "$file")" in text/plain) echo "Text file" ;; text/html) echo "HTML file" ;; image/*) echo "Image file: $(file -b --mime-type "$file")" ;; application/zip) echo "ZIP archive" ;; application/pdf) echo "PDF document" ;; application/json) echo "JSON file" ;; application/x-shellscript) echo "Shell script" ;; *) echo "Other: $(file -b --mime-type "$file")" ;; esac}
# Usagefor file in "$@"; do echo -n "$file: " detect_file_type "$file"doneSignal Handling
Section titled “Signal Handling”Signal Processing with Case
Section titled “Signal Processing with Case”#!/usr/bin/env bash# Handle signalshandle_signal() { local signal="$1"
case "$signal" in SIGTERM) echo "Received SIGTERM, shutting down gracefully..." cleanup exit 0 ;; SIGINT) echo "Received Ctrl+C, stopping..." cleanup exit 0 ;; SIGHUP) echo "Received SIGHUP, reloading configuration..." reload_config ;; *) echo "Received unknown signal: $signal" ;; esac}
cleanup() { echo "Cleaning up..." # Add cleanup tasks rm -f /tmp/app.lock}
reload_config() { echo "Reloading configuration..." # Add reload tasks}
# Register signal handlerstrap 'handle_signal SIGTERM' TERMtrap 'handle_signal SIGINT' INTtrap 'handle_signal SIGHUP' HUP
echo "Script running... Press Ctrl+C to stop"echo "PID: $$"
# Simulate long-running processwhile true; do sleep 1doneExit Codes Handling
Section titled “Exit Codes Handling”Mapping Exit Codes
Section titled “Mapping Exit Codes”#!/usr/bin/env bashhandle_exit_code() { local exit_code=$1
case "$exit_code" in 0) echo "Success" ;; 1) echo "General error" ;; 2) echo "Misuse of shell command" ;; 126) echo "Command not executable" ;; 127) echo "Command not found" ;; 128) echo "Invalid exit argument" ;; 130) echo "Script terminated by Ctrl+C (SIGINT)" ;; *) echo "Unknown exit code: $exit_code" ;; esac}
# Example: Run command and handle exit codegrep "pattern" file.txthandle_exit_code $?Advanced Patterns
Section titled “Advanced Patterns”Regex-like Patterns (Bash 4+)
Section titled “Regex-like Patterns (Bash 4+)”#!/usr/bin/env bash# Extended pattern matchingshopt -s extglob
read -p "Enter filename: " filename
case "$filename" in # Starts with backup backup*) echo "Backup file" ;; # Ends with .log or .txt *.log|*.txt) echo "Log or text file" ;; # Contains date pattern *-202[0-9]-[0-9][0-9]-*) echo "Dated file" ;; # Exactly 3 characters ???) echo "Three character filename" ;; # Any other *) echo "Other file" ;;esacCombining with Functions
Section titled “Combining with Functions”#!/usr/bin/env bashdeploy() { local environment="$1" local version="$2"
case "$environment" in production) echo "Deploying to PRODUCTION: $version" confirm_deployment ;; staging) echo "Deploying to STAGING: $version" ;; development|dev) echo "Deploying to DEV: $version" ;; *) echo "Unknown environment: $environment" return 1 ;; esac}
confirm_deployment() { local confirm read -p "Confirm production deployment? (yes/no): " confirm case "$confirm" in yes|Yes|YES) echo "Deploying..." ;; *) echo "Deployment cancelled" exit 1 ;; esac}
# Usagedeploy "$1" "$2"Real-World Examples
Section titled “Real-World Examples”Complete Deployment Script
Section titled “Complete Deployment Script”#!/usr/bin/env bashset -euo pipefail
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"readonly SCRIPT_NAME="$(basename "$0")"
show_usage() { cat << EOFUsage: $SCRIPT_NAME [COMMAND] [OPTIONS]
Commands: deploy <environment> <version> Deploy application rollback <environment> Rollback to previous version status Show deployment status health Check application health
Options: -h, --help Show this help message -f, --force Force operation -v, --verbose Verbose output
Examples: $SCRIPT_NAME deploy production v1.2.3 $SCRIPT_NAME rollback staging $SCRIPT_NAME status
EOF}
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"}
deploy() { local environment="$1" local version="$2"
log "Starting deployment: $environment $version"
case "$environment" in production) log "PRODUCTION deployment - extra checks" check_production_prerequisites ;; staging) log "Staging deployment" ;; development|dev) log "Development deployment" ;; *) log "Invalid environment: $environment" return 1 ;; esac
log "Pulling image..." docker pull "myapp:$version"
log "Stopping old containers..." docker-compose down
log "Starting new containers..." docker-compose up -d
log "Deployment complete"}
check_production_prerequisites() { local confirm read -p "This is a PRODUCTION deployment. Are you sure? (yes/no): " confirm case "$confirm" in yes|Yes|YES) return 0 ;; *) log "Deployment cancelled" exit 1 ;; esac}
rollback() { local environment="$1" log "Rolling back $environment" docker-compose down docker-compose up -d}
status() { log "Checking status..." docker-compose ps}
health() { log "Checking health..." curl -f http://localhost:8080/health || exit 1}
# MainCOMMAND="${1:-}"
case "$COMMAND" in deploy) deploy "$2" "$3" ;; rollback) rollback "$2" ;; status) status ;; health) health ;; -h|--help) show_usage ;; *) show_usage exit 1 ;;esacSummary
Section titled “Summary”In this chapter, you learned about:
- ✅ Basic case statement syntax
- ✅ Pattern matching with wildcards
- ✅ Multiple patterns with |
- ✅ Character classes
- ✅ Command-line argument parsing
- ✅ Menu systems
- ✅ Service management scripts
- ✅ File type detection
- ✅ Signal handling
- ✅ Exit code handling
- ✅ Advanced patterns
- ✅ Combining case with functions
- ✅ Real-world DevOps examples
Exercises
Section titled “Exercises”Level 1: Basics
Section titled “Level 1: Basics”- Write a script that converts number grades to letter grades using case
- Create a script that processes command-line flags using case
- Write a menu-driven calculator using case
Level 2: Intermediate
Section titled “Level 2: Intermediate”- Create a service management script using case
- Write a file type detection script
- Implement a deployment script with environment selection
Level 3: Advanced
Section titled “Level 3: Advanced”- Create a complete CLI tool with multiple commands
- Implement signal handling with case
- Build an interactive menu system with case
Next Steps
Section titled “Next Steps”Continue to the next chapter to learn about loops.
Previous Chapter: Conditionals Next Chapter: Loops