Claude
Skills
Sign in
Back

bash-script-framework

Included with Lifetime
$97 forever

Create organized bash script structure with color output, menu systems, error handling, and cross-platform support. Standardizes CLI tooling.

workspace-hub

What this skill does


# Bash Script Framework

> Create standardized bash scripts with menus, colors, and error handling.

## Quick Start

```bash
# Create script directory structure
/bash-script-framework init

# Create new script with menu
/bash-script-framework new my-script --menu

# Add to existing scripts directory
/bash-script-framework add utility-script
```

## When to Use

**USE when:**
- Creating CLI tools for repository
- Building menu-driven automation
- Standardizing script organization
- Cross-platform script development

**DON'T USE when:**
- Python script is more appropriate
- Simple one-liner needed
- Windows-only environment

## Prerequisites

- Bash 4.0+
- Unix-like environment (Linux, macOS, WSL)

## Overview

Creates organized bash scripts following workspace-hub patterns:

1. **Color utilities** - Consistent terminal output
2. **Menu systems** - Multi-level navigation
3. **Error handling** - Proper exit codes
4. **Logging** - Timestamped output
5. **Cross-platform** - Linux/macOS/WSL support

## Directory Structure

```
scripts/
├── workspace                  # Main entry point
├── lib/
│   ├── colors.sh             # Color definitions
│   ├── logging.sh            # Logging utilities
│   ├── menu.sh               # Menu system
│   └── utils.sh              # General utilities
├── bash/
│   ├── git/                  # Git operations
│   └── dev/                  # Development tools
├── python/                   # Python utilities
└── powershell/               # Windows scripts
```

## Core Templates

### 1. Color Library (lib/colors.sh)

```bash
#!/bin/bash
# lib/colors.sh - Color definitions for terminal output
# Source this file: source lib/colors.sh

# Reset
NC='\033[0m'              # No Color / Reset

# Regular Colors
BLACK='\033[0;30m'
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[0;37m'

# Bold Colors
BOLD_BLACK='\033[1;30m'
BOLD_RED='\033[1;31m'
BOLD_GREEN='\033[1;32m'
BOLD_YELLOW='\033[1;33m'
BOLD_BLUE='\033[1;34m'
BOLD_MAGENTA='\033[1;35m'
BOLD_CYAN='\033[1;36m'
BOLD_WHITE='\033[1;37m'

# Background Colors
BG_BLACK='\033[40m'
BG_RED='\033[41m'
BG_GREEN='\033[42m'
BG_YELLOW='\033[43m'
BG_BLUE='\033[44m'
BG_MAGENTA='\033[45m'
BG_CYAN='\033[46m'
BG_WHITE='\033[47m'

# Formatting
BOLD='\033[1m'
DIM='\033[2m'
UNDERLINE='\033[4m'
BLINK='\033[5m'
REVERSE='\033[7m'

# Status indicators
SUCCESS="${GREEN}✓${NC}"
FAIL="${RED}✗${NC}"
WARN="${YELLOW}⚠${NC}"
INFO="${BLUE}ℹ${NC}"
ARROW="${CYAN}→${NC}"

# Print colored text
print_color() {
    local color="$1"
    local message="$2"
    echo -e "${color}${message}${NC}"
}

# Status messages
print_success() { echo -e "${SUCCESS} ${GREEN}$1${NC}"; }
print_error() { echo -e "${FAIL} ${RED}$1${NC}" >&2; }
print_warning() { echo -e "${WARN} ${YELLOW}$1${NC}"; }
print_info() { echo -e "${INFO} ${BLUE}$1${NC}"; }

# Headers and separators
print_header() {
    local title="$1"
    local width=${2:-60}
    local line=$(printf '═%.0s' $(seq 1 $width))
    echo -e "\n${BOLD_CYAN}╔${line}╗${NC}"
    printf "${BOLD_CYAN}║${NC} ${BOLD_WHITE}%-$((width-2))s${NC} ${BOLD_CYAN}║${NC}\n" "$title"
    echo -e "${BOLD_CYAN}╚${line}╝${NC}\n"
}

print_separator() {
    local width=${1:-60}
    local char=${2:-─}
    printf "${DIM}%${width}s${NC}\n" | tr ' ' "$char"
}

# Check if colors are supported
supports_colors() {
    if [[ -t 1 ]] && [[ -n "$TERM" ]] && [[ "$TERM" != "dumb" ]]; then
        return 0
    fi
    return 1
}

# Disable colors if not supported
if ! supports_colors; then
    NC='' RED='' GREEN='' YELLOW='' BLUE='' MAGENTA='' CYAN='' WHITE=''
    BOLD='' DIM='' SUCCESS='[OK]' FAIL='[FAIL]' WARN='[WARN]' INFO='[INFO]'
fi
```

### 2. Logging Library (lib/logging.sh)

```bash
#!/bin/bash
# lib/logging.sh - Logging utilities
# Source this file after colors.sh

# Log levels
LOG_LEVEL_DEBUG=0
LOG_LEVEL_INFO=1
LOG_LEVEL_WARN=2
LOG_LEVEL_ERROR=3

# Current log level (default: INFO)
CURRENT_LOG_LEVEL=${CURRENT_LOG_LEVEL:-$LOG_LEVEL_INFO}

# Log file (optional)
LOG_FILE="${LOG_FILE:-}"

# Timestamp format
timestamp() {
    date "+%Y-%m-%d %H:%M:%S"
}

# Internal log function
_log() {
    local level="$1"
    local level_name="$2"
    local color="$3"
    local message="$4"

    if [[ $level -ge $CURRENT_LOG_LEVEL ]]; then
        local ts=$(timestamp)
        local formatted="[${ts}] [${level_name}] ${message}"

        # Output to console
        echo -e "${color}${formatted}${NC}"

        # Output to log file if configured
        if [[ -n "$LOG_FILE" ]]; then
            echo "${formatted}" >> "$LOG_FILE"
        fi
    fi
}

# Log functions
log_debug() { _log $LOG_LEVEL_DEBUG "DEBUG" "$DIM" "$1"; }
log_info() { _log $LOG_LEVEL_INFO "INFO " "$BLUE" "$1"; }
log_warn() { _log $LOG_LEVEL_WARN "WARN " "$YELLOW" "$1"; }
log_error() { _log $LOG_LEVEL_ERROR "ERROR" "$RED" "$1"; }

# Log with custom prefix
log_step() {
    local step="$1"
    local message="$2"
    echo -e "${CYAN}[Step ${step}]${NC} ${message}"
}

log_progress() {
    local current="$1"
    local total="$2"
    local message="${3:-Processing}"
    local percent=$((current * 100 / total))
    printf "\r${CYAN}%s${NC}: [%3d%%] %d/%d" "$message" "$percent" "$current" "$total"
}

log_progress_done() {
    echo ""  # New line after progress
}

# Set log level
set_log_level() {
    case "$1" in
        debug|DEBUG) CURRENT_LOG_LEVEL=$LOG_LEVEL_DEBUG ;;
        info|INFO)   CURRENT_LOG_LEVEL=$LOG_LEVEL_INFO ;;
        warn|WARN)   CURRENT_LOG_LEVEL=$LOG_LEVEL_WARN ;;
        error|ERROR) CURRENT_LOG_LEVEL=$LOG_LEVEL_ERROR ;;
        *) log_error "Unknown log level: $1" ;;
    esac
}

# Enable file logging
enable_file_logging() {
    LOG_FILE="${1:-logs/script.log}"
    mkdir -p "$(dirname "$LOG_FILE")"
    log_info "Logging to file: $LOG_FILE"
}
```

### 3. Menu System (lib/menu.sh)

```bash
#!/bin/bash
# lib/menu.sh - Menu system utilities
# Source after colors.sh

# Display menu and get selection
show_menu() {
    local title="$1"
    shift
    local options=("$@")

    print_header "$title"

    local i=1
    for option in "${options[@]}"; do
        if [[ "$option" == "---" ]]; then
            print_separator 40
        else
            printf "  ${CYAN}%2d)${NC} %s\n" "$i" "$option"
            ((i++))
        fi
    done

    echo ""
    printf "  ${CYAN} 0)${NC} ${DIM}Exit / Back${NC}\n"
    echo ""

    read -p "$(echo -e ${BOLD}Select option: ${NC})" choice
    echo "$choice"
}

# Confirm action
confirm() {
    local message="${1:-Are you sure?}"
    local default="${2:-n}"

    if [[ "$default" == "y" ]]; then
        read -p "$(echo -e ${YELLOW}$message [Y/n]: ${NC})" response
        response=${response:-y}
    else
        read -p "$(echo -e ${YELLOW}$message [y/N]: ${NC})" response
        response=${response:-n}
    fi

    [[ "$response" =~ ^[Yy]$ ]]
}

# Prompt for input
prompt_input() {
    local message="$1"
    local default="${2:-}"
    local result

    if [[ -n "$default" ]]; then
        read -p "$(echo -e ${CYAN}$message [$default]: ${NC})" result
        result=${result:-$default}
    else
        read -p "$(echo -e ${CYAN}$message: ${NC})" result
    fi

    echo "$result"
}

# Select from list
select_from_list() {
    local title="$1"
    shift
    local items=("$@")

    echo -e "\n${BOLD}$title${NC}\n"

    local i=1
    for item in "${items[@]}"; do
        printf "  ${CYAN}%2d)${NC} %s\n" "$i" "$item"
        ((i++))
    done

    echo ""
    read -p "$(echo -e ${BOLD}Select [1-${#items[@]}]: ${NC})" choice

    if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#items[@]} ]]; then
        echo "${items[$((choice-1))]}"
    else
        echo ""
    fi
}

# Multi-select from list
multi_select() {
    local title="$1"
    shift
    local items=("$@")
    local selected=()

    echo -e "\n${BOLD}$title${NC}"
    echo -e "${DIM}(Enter numbers separated by spaces, or 'all')${NC}\n"

    local i=1
    for item in "${items[@]}"; do

Related in workspace-hub