bash-script-framework
Create organized bash script structure with color output, menu systems, error handling, and cross-platform support. Standardizes CLI tooling.
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
data-validation-reporter
IncludedGenerate interactive validation reports with quality scoring, missing data analysis, and type checking. Combines Pandas validation, Plotly visualization, and YAML configuration for comprehensive data quality reporting.
claude-reflection
IncludedSelf-improvement and learning skill that helps Claude learn from user interactions, corrections, and preferences
interactive-report-generator
IncludedGenerate interactive HTML reports with Plotly visualizations from data analysis results. Supports dashboards, charts, and professional styling.
yaml-workflow-executor
IncludedExecute data processing workflows defined in YAML configuration files. Supports data loading, transformation, validation, and reporting pipelines.
pytest-fixture-generator
IncludedGenerate standardized pytest configuration with fixtures, markers, and coverage settings. Creates conftest.py and pytest.ini for workspace-hub compliant testing.
agent-os-framework
IncludedGenerate standardized .agent-os directory structure with product documentation, mission, tech-stack, roadmap, and decision records. Enables AI-native workflows.