How to Parse Command Line Arguments in WP-CLI Bash Scripts

When building automation scripts for WordPress using WP-CLI, the ability to parse command line arguments effectively transforms rigid scripts into flexible, reusable tools. Whether you’re managing multiple sites or creating custom deployment workflows, understanding argument parsing is essential for professional WordPress development.

Why Parse Arguments in WP-CLI Scripts?

Command line argument parsing enables your Bash scripts to accept dynamic input, making them adaptable to different scenarios without code modifications. Instead of hardcoding site URLs, environment types, or backup paths, you can pass these values as arguments when executing your scripts.

This approach brings several advantages: increased script reusability, reduced maintenance overhead, better error handling, and improved user experience. A well-designed script with proper argument parsing can serve multiple purposes across different WordPress installations.

Understanding Positional Parameters

The simplest form of argument parsing uses positional parameters. In Bash, arguments passed to a script are automatically assigned to special variables: $1 for the first argument, $2 for the second, and so on. The $0 variable contains the script name itself.

#!/bin/bash
# Simple WP-CLI backup script with positional parameters

SITE_PATH=$1
BACKUP_DIR=$2

wp --path="$SITE_PATH" db export "$BACKUP_DIR/database-$(date +%Y%m%d).sql"

Execute this script with: ./backup.sh /var/www/html /backups

While positional parameters work for simple cases, they have limitations. Users must remember the exact order of arguments, and the script offers no built-in way to handle optional parameters or provide helpful usage information.

Using getopts for Named Options

The getopts command provides a more sophisticated approach to argument parsing, allowing you to define named options with single-character flags. This method significantly improves script usability and maintainability.

#!/bin/bash
# WP-CLI deployment script with getopts

usage() {
    echo "Usage: $0 -p <path> -e <environment> [-b]"
    echo "  -p    WordPress installation path"
    echo "  -e    Environment (dev|staging|prod)"
    echo "  -b    Create backup before deployment"
    exit 1
}

BACKUP=false

while getopts "p:e:bh" opt; do
    case $opt in
        p) WP_PATH="$OPTARG" ;;
        e) ENVIRONMENT="$OPTARG" ;;
        b) BACKUP=true ;;
        h) usage ;;
        \?) echo "Invalid option: -$OPTARG" >&2; usage ;;
        :) echo "Option -$OPTARG requires an argument" >&2; usage ;;
    esac
done

# Validate required arguments
if [[ -z "$WP_PATH" ]] || [[ -z "$ENVIRONMENT" ]]; then
    echo "Error: Missing required arguments"
    usage
fi

# Script logic continues here
if [[ "$BACKUP" == true ]]; then
    wp --path="$WP_PATH" db export "backup-pre-deploy-$(date +%Y%m%d-%H%M%S).sql"
fi

In this example, options followed by a colon (like p: and e:) require arguments, while standalone letters (like b) act as flags. The OPTARG variable holds the value passed to options requiring arguments.

Advanced Argument Validation

Robust scripts validate input before processing. Argument validation prevents errors, protects against malicious input, and provides clear feedback when users make mistakes.

#!/bin/bash
# WP-CLI site migration script with validation

validate_path() {
    if [[ ! -d "$1" ]]; then
        echo "Error: Path '$1' does not exist"
        exit 1
    fi

    if [[ ! -f "$1/wp-config.php" ]]; then
        echo "Error: '$1' is not a WordPress installation"
        exit 1
    fi
}

validate_environment() {
    local env=$1
    case $env in
        dev|development|staging|production|prod)
            return 0
            ;;
        *)
            echo "Error: Invalid environment '$env'"
            echo "Allowed values: dev, staging, production"
            exit 1
            ;;
    esac
}

# After parsing arguments with getopts
validate_path "$WP_PATH"
validate_environment "$ENVIRONMENT"

Handling Long-Form Options

While getopts handles short options well, it doesn’t natively support long-form options like --path or --environment. For scripts requiring both short and long options, you can implement manual parsing:

#!/bin/bash

while [[ $# -gt 0 ]]; do
    case $1 in
        -p|--path)
            WP_PATH="$2"
            shift 2
            ;;
        -e|--environment)
            ENVIRONMENT="$2"
            shift 2
            ;;
        --dry-run)
            DRY_RUN=true
            shift
            ;;
        -h|--help)
            usage
            ;;
        *)
            echo "Unknown option: $1"
            usage
            ;;
    esac
done

The shift command removes processed arguments from the parameter list, allowing the loop to progress through all provided options.

Practical Example: Multi-Site Update Script

Here’s a complete example demonstrating argument parsing in a real-world WP-CLI script:

#!/bin/bash
# Update multiple WordPress sites with flexible options

set -euo pipefail

usage() {
    cat << EOF
Usage: $0 -s <sites> [OPTIONS]

Required:
    -s, --sites       Comma-separated list of site paths

Options:
    -c, --core        Update WordPress core
    -p, --plugins     Update plugins
    -t, --themes      Update themes
    -a, --all         Update everything
    --exclude-plugin  Plugin to exclude (can be used multiple times)
    --dry-run         Show what would be updated without making changes
    -h, --help        Display this help message

Example:
    $0 -s "/var/www/site1,/var/www/site2" --all --exclude-plugin akismet
EOF
    exit 1
}

# Initialize variables
SITES=""
UPDATE_CORE=false
UPDATE_PLUGINS=false
UPDATE_THEMES=false
DRY_RUN=false
EXCLUDED_PLUGINS=()

# Parse arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -s|--sites) SITES="$2"; shift 2 ;;
        -c|--core) UPDATE_CORE=true; shift ;;
        -p|--plugins) UPDATE_PLUGINS=true; shift ;;
        -t|--themes) UPDATE_THEMES=true; shift ;;
        -a|--all) UPDATE_CORE=true; UPDATE_PLUGINS=true; UPDATE_THEMES=true; shift ;;
        --exclude-plugin) EXCLUDED_PLUGINS+=("$2"); shift 2 ;;
        --dry-run) DRY_RUN=true; shift ;;
        -h|--help) usage ;;
        *) echo "Unknown option: $1"; usage ;;
    esac
done

# Validate required arguments
if [[ -z "$SITES" ]]; then
    echo "Error: Sites parameter is required"
    usage
fi

# Convert comma-separated sites to array
IFS=',' read -ra SITE_ARRAY <<< "$SITES"

# Process each site
for site in "${SITE_ARRAY[@]}"; do
    echo "Processing: $site"

    if [[ "$UPDATE_CORE" == true ]]; then
        if [[ "$DRY_RUN" == true ]]; then
            wp --path="$site" core check-update
        else
            wp --path="$site" core update
        fi
    fi

    if [[ "$UPDATE_PLUGINS" == true ]]; then
        EXCLUDE_ARGS=""
        for plugin in "${EXCLUDED_PLUGINS[@]}"; do
            EXCLUDE_ARGS+=" --exclude=$plugin"
        done

        if [[ "$DRY_RUN" == true ]]; then
            wp --path="$site" plugin list --update=available
        else
            wp --path="$site" plugin update --all $EXCLUDE_ARGS
        fi
    fi

    if [[ "$UPDATE_THEMES" == true ]]; then
        if [[ "$DRY_RUN" == true ]]; then
            wp --path="$site" theme list --update=available
        else
            wp --path="$site" theme update --all
        fi
    fi
done

echo "Update process completed successfully"

This script demonstrates several best practices: comprehensive usage documentation, boolean flags for optional features, array handling for multiple values, validation of required parameters, and safe execution with set -euo pipefail.

Best Practices for Argument Parsing

Always provide clear usage documentation that users can access with -h or --help. Validate all input before processing to catch errors early. Use meaningful variable names that clarify the purpose of each argument.

Set default values for optional parameters to ensure predictable behavior. Implement proper error handling with informative messages. Consider the order of operations when multiple flags interact.

For production scripts, add the set -euo pipefail directive at the beginning. This makes your script exit on errors, prevents using undefined variables, and ensures pipeline failures are caught.

Testing Your Argument Parsing

Test your scripts with various input combinations: missing required arguments, invalid values, conflicting options, and edge cases. Create a test suite that validates expected behavior:

# Test missing required argument
./script.sh  # Should show usage

# Test invalid environment
./script.sh -p /var/www/html -e invalid  # Should error

# Test dry run mode
./script.sh -s "/var/www/site1" --all --dry-run  # Should only show what would change

Leave a Reply

Your email address will not be published. Required fields are marked *