Skip to main content

Overview

The Script Template (script-template.sh) provides a standardized starting point for creating new bash scripts. It includes pre-configured color codes, logging functions, argument parsing, and follows bash best practices with proper error handling.
Use this template as the foundation for all new bash scripts to ensure consistency, maintainability, and robust error handling across your script collection.

Template Structure

The template is organized into logical sections:
#!/bin/bash
# script-name.sh - Brief description

# Usage comments
# Options documentation
# Examples

set -eo pipefail         # Error handling

# COLORS                 # Color definitions
# CONFIGURATION          # Global variables
# FUNCTIONS             # Helper functions
# ARG PARSING           # Command-line argument handling
# MAIN LOGIC            # Core script logic
# EXECUTION             # Entry point

Getting Started

Creating a New Script

1

Copy the Template

cp script-template.sh my-new-script.sh
chmod +x my-new-script.sh
2

Update the Header

Modify the script name, description, usage, and examples:
my-new-script.sh
#!/bin/bash
# my-new-script.sh - Does something awesome
#
# Usage:
#   ./my-new-script.sh [OPTIONS] [ARGS]
#
# Options:
#   -h, --help      Show this help message
#   -f, --file      Input file path
3

Implement Main Logic

Add your script’s functionality in the main() function:
main() {
  log "Starting my awesome task..."
  
  # Your code here
  
  success "Task completed successfully"
}
4

Add Custom Arguments

Extend the argument parsing section as needed:
-f|--file)
  FILE="$2"
  shift 2
  ;;

Built-in Features

Error Handling

The template uses set -eo pipefail for strict error handling:
-e
flag
Exit immediately if any command fails (non-zero exit code)
-o pipefail
flag
Return the exit code of the first failed command in a pipeline
set -eo pipefail
Without these flags:
# Without -e: script continues even after failure
rm important-file.txt
echo "File deleted"  # Runs even if rm failed

# Without pipefail: only last command's exit code is checked
cat missing.txt | grep error  # Succeeds if grep works, ignoring cat failure
With these flags:
# With -e: script exits on first failure
rm important-file.txt  # If this fails, script stops
echo "File deleted"    # Never executed

# With pipefail: entire pipeline fails if any command fails
cat missing.txt | grep error  # Fails if cat fails, even if grep would succeed

Color Definitions

Pre-defined ANSI color codes for terminal output:
Color Variables
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'  # No Color
Usage Example:
echo -e "${GREEN}Success!${NC}"
echo -e "${RED}${BOLD}Error:${NC} Something went wrong"
echo -e "${DIM}Debug info${NC}"

Logging Functions

The template includes five pre-built logging functions:
# General information with blue icon
log "Starting process..."
# Output: ℹ Starting process...

Function Implementations

Helper Functions
log() {
  echo -e "${BLUE}ℹ${NC} $*"
}

success() {
  echo -e "${GREEN}✓${NC} $*"
}

error() {
  echo -e "${RED}✗${NC} $*" >&2
}

warning() {
  echo -e "${YELLOW}⚠${NC} $*"
}

debug() {
  if [[ $DEBUG -eq 1 ]]; then
    echo -e "${DIM}[DEBUG]${NC} $*"
  fi
}

Configuration Variables

Global configuration with sensible defaults:
Configuration Section
DEBUG=0        # Enable debug output
VERBOSE=0      # Enable verbose output
Add custom configuration variables here:
Custom Config
DEBUG=0
VERBOSE=0
OUTPUT_DIR="./output"
MAX_RETRIES=3
TIMEOUT=30

Help System

Built-in help function with formatted output:
show_help() Function
show_help() {
  cat << EOF
${BOLD}${CYAN}script-name.sh${NC} - Brief description

${BOLD}USAGE:${NC}
  ./script-name.sh [OPTIONS] [ARGS]

${BOLD}OPTIONS:${NC}
  ${GREEN}-h, --help${NC}      Show this help message
  ${GREEN}-d, --debug${NC}     Enable debug mode (dry-run)
  ${GREEN}-v, --verbose${NC}   Verbose output

${BOLD}EXAMPLES:${NC}
  ${DIM}# Basic usage${NC}
  ./script-name.sh
  
  ${DIM}# Debug mode${NC}
  ./script-name.sh --debug

${BOLD}DESCRIPTION:${NC}
  Add a longer description here explaining what your script does,
  its purpose, and any important details users should know.

EOF
  exit 0
}
Customize the help output by editing the show_help() function. Add sections for requirements, configuration files, examples, or troubleshooting.

Argument Parsing

Robust command-line argument handling with a while loop:
Argument Parser
while [[ $# -gt 0 ]]; do
  case $1 in
    -h|--help)
      show_help
      ;;
    -d|--debug)
      DEBUG=1
      shift
      ;;
    -v|--verbose)
      VERBOSE=1
      shift
      ;;
    *)
      error "Unknown option: $1"
      echo "Use --help for usage information"
      exit 1
      ;;
  esac
done
Flag Arguments (no value):
-q|--quiet)
  QUIET=1
  shift
  ;;
Value Arguments (requires a value):
-f|--file)
  FILE="$2"
  shift 2
  ;;
Optional Value Arguments:
-o|--output)
  OUTPUT="${2:-default.txt}"
  shift 2
  ;;
Multiple Values:
-i|--input)
  INPUTS+=("$2")
  shift 2
  ;;

Usage Examples

Basic Script Structure

my-backup.sh
#!/bin/bash
# my-backup.sh - Backs up important directories

set -eo pipefail

# Load template helpers...

main() {
  log "Starting backup..."
  
  if [[ $DEBUG -eq 1 ]]; then
    debug "Debug mode enabled"
    warning "This is a dry-run, no changes will be made"
    # Show what would happen
  else
    # Do actual backup
    tar -czf backup.tar.gz ~/documents
    success "Backup created: backup.tar.gz"
  fi
}

main "$@"

Script with File Input

process-file.sh
#!/bin/bash
# process-file.sh - Processes a data file

set -eo pipefail

# Colors and helpers...

FILE=""

# Add file argument
while [[ $# -gt 0 ]]; do
  case $1 in
    -f|--file)
      FILE="$2"
      shift 2
      ;;
    # ... other arguments
  esac
done

main() {
  if [[ -z "$FILE" ]]; then
    error "File is required"
    echo "Use: $0 --file input.txt"
    exit 1
  fi
  
  if [[ ! -f "$FILE" ]]; then
    error "File not found: $FILE"
    exit 1
  fi
  
  log "Processing file: $FILE"
  # Process the file...
  success "File processed successfully"
}

main

Script with Configuration File

deploy.sh
#!/bin/bash
# deploy.sh - Deploys application to server

set -eo pipefail

# Colors and helpers...

CONFIG_FILE=".deploy.conf"

# Load configuration
if [[ -f "$CONFIG_FILE" ]]; then
  source "$CONFIG_FILE"
  success "Loaded configuration from $CONFIG_FILE"
else
  warning "No config file found, using defaults"
fi

main() {
  log "Deploying to ${SERVER:-localhost}..."
  # Deployment logic...
  success "Deployment complete"
}

main

Best Practices Included

#!/bin/bash
Ensures the script runs with bash, not sh or another shell.
Clear documentation at the top:
  • Script name and description
  • Usage instructions
  • Available options
  • Example commands
set -eo pipefail
Strict error handling prevents silent failures.
Logical sections with clear headers:
  • Colors
  • Configuration
  • Functions
  • Argument parsing
  • Main logic
-h|--help)
  show_help
  ;;
Every script should have a help option.
debug "Variable value: $VAR"
Built-in debug mode for troubleshooting.

Advanced Customizations

Add Dependency Checking

Dependency Check
check_dependencies() {
  local deps=("curl" "jq" "git")
  local missing=()
  
  for dep in "${deps[@]}"; do
    if ! command -v "$dep" &> /dev/null; then
      missing+=("$dep")
    fi
  done
  
  if [[ ${#missing[@]} -gt 0 ]]; then
    error "Missing dependencies: ${missing[*]}"
    echo "Install with: apt install ${missing[*]}"
    exit 1
  fi
}

main() {
  check_dependencies
  # Rest of script...
}

Add Progress Indicator

Progress Spinner
spinner() {
  local pid=$1
  local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
  local i=0
  
  while kill -0 $pid 2>/dev/null; do
    printf "\r${CYAN}%s${NC} Processing..." "${spin:$i:1}"
    i=$(( (i+1) % ${#spin} ))
    sleep 0.1
  done
  printf "\r${GREEN}✓${NC} Complete\n"
}

# Usage
long_running_task &
spinner $!

Add Cleanup Handler

Cleanup on Exit
TEMP_DIR=""

cleanup() {
  if [[ -n "$TEMP_DIR" ]] && [[ -d "$TEMP_DIR" ]]; then
    debug "Cleaning up temp directory: $TEMP_DIR"
    rm -rf "$TEMP_DIR"
  fi
}

trap cleanup EXIT INT TERM

main() {
  TEMP_DIR=$(mktemp -d)
  debug "Created temp directory: $TEMP_DIR"
  
  # Script logic using $TEMP_DIR
  # Cleanup happens automatically on exit
}

Add Logging to File

File Logging
LOG_FILE="/var/log/my-script.log"

# Override logging functions
log() {
  local msg="${BLUE}ℹ${NC} $*"
  echo -e "$msg"
  echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $*" >> "$LOG_FILE"
}

error() {
  local msg="${RED}✗${NC} $*"
  echo -e "$msg" >&2
  echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $*" >> "$LOG_FILE"
}

Template Variations

Minimal Template

For simple scripts, use a stripped-down version:
minimal-template.sh
#!/bin/bash
set -eo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

error() { echo -e "${RED}✗${NC} $*" >&2; }
success() { echo -e "${GREEN}✓${NC} $*"; }

main() {
  # Your code here
  success "Done"
}

main "$@"

Interactive Template

For scripts requiring user input:
interactive-template.sh
#!/bin/bash
set -eo pipefail

# Colors and helpers...

ask_yes_no() {
  local prompt="$1"
  local default="${2:-n}"
  
  read -p "${prompt} [y/n] (default: ${default}): " response
  response="${response:-$default}"
  
  [[ "$response" =~ ^[Yy]$ ]]
}

main() {
  log "Starting interactive setup..."
  
  if ask_yes_no "Continue with installation?" "y"; then
    success "Proceeding..."
  else
    warning "Installation cancelled"
    exit 0
  fi
}

main

Comparison with Other Scripts

See how the template compares to production scripts:

GDrive Ingest

Complex script built on this template with interactive UI, API calls, and progress tracking

Power Guard

Minimal monitoring script showing when you don’t need the full template

Testing Your Script

Always test with debug mode first:
# Test argument parsing
./my-script.sh --help
./my-script.sh --debug

# Test error handling
./my-script.sh --invalid-flag

# Test with ShellCheck
shellcheck my-script.sh
Install ShellCheck for static analysis:
# Ubuntu/Debian
apt install shellcheck

# macOS
brew install shellcheck

Quick Reference

Color Usage

echo -e "${RED}Error${NC}"
echo -e "${GREEN}Success${NC}"
echo -e "${YELLOW}Warning${NC}"
echo -e "${BLUE}Info${NC}"
echo -e "${CYAN}Highlight${NC}"
echo -e "${BOLD}Bold${NC}"
echo -e "${DIM}Dimmed${NC}"

Logging Functions

log "General information"
success "Operation succeeded"
error "Operation failed"
warning "Potential issue"
debug "Debug information"  # Only shown when DEBUG=1

Common Patterns

# Check if file exists
if [[ ! -f "$FILE" ]]; then
  error "File not found: $FILE"
  exit 1
fi

# Check if command exists
if ! command -v curl &> /dev/null; then
  error "curl is required"
  exit 1
fi

# Check if variable is set
if [[ -z "$VAR" ]]; then
  error "VAR is required"
  exit 1
fi

Bash Best Practices

Google’s Shell Style Guide

ShellCheck

Shell script analysis tool

Advanced Bash Scripting

Comprehensive bash scripting guide