Shell Libraries Architecture¶
The dotfiles repository provides three system-wide shell libraries for consistent, production-grade script development. Each library serves a distinct purpose and can be used independently or combined as needed.
Library Overview¶
logging.sh - Status Messages with Log Prefixes¶
Location: ~/.local/shell/logging.sh
Purpose: Core logging for scripts that output status messages and may be logged/monitored
Size: ~116 lines
When to use:
- Scripts run unattended or in CI/CD
- Installation/update scripts that need logging
- Any script whose output might be piped to log files
- Scripts that need parseable output for tools like logsift
Functions:
log_info(message)- [INFO] + cyan + ● iconlog_success(message)- [INFO] + green + ✓ iconlog_warning(message)- [WARNING] + yellow + ▲ icon → stderrlog_error(message, [file], [line])- [ERROR] + red + ✗ icon → stderrlog_debug(message)- [DEBUG] → stderr (only if DEBUG=true)log_fatal(message, [file], [line])- [FATAL] + red + ✗ icon → stderr, exits 1die(message)- Calls log_error then exit 1
Output format: Always includes [LEVEL] prefix for log parsers while remaining visually beautiful with colors and unicode icons.
Example:
#!/usr/bin/env bash
source "$HOME/.local/shell/logging.sh"
log_info "Starting backup process..."
log_success "Backed up 156 files"
log_warning "Skipped 3 files (permissions denied)"
log_error "Failed to backup config.yml" "$BASH_SOURCE" "$LINENO"
formatting.sh - Visual Structure for Interactive Output¶
Location: ~/.local/shell/formatting.sh
Purpose: Visual formatting for interactive scripts with headers, sections, banners
Size: ~760 lines
When to use:
- Interactive scripts run by humans at terminal
- Scripts with visual sections/phases
- Menu systems and interactive tools
- Scripts that prioritize visual appeal over parseability
Structural Functions:
print_header(text, [color])- Thick borders, left-alignedprint_section(text, [color])- Thin underlineprint_banner(text, [color])- Double bars (═)print_title(text, [color])- Centered, full-width- Variants:
_success,_error,_warning,_infowith emojis
Status Functions (for visual-only scripts):
print_success(message)- Green + ✓ icon (no [LEVEL] prefix)print_error(message)- Red + ✗ icon (no [LEVEL] prefix)print_warning(message)- Yellow + ▲ icon (no [LEVEL] prefix)print_info(message)- Cyan + ● icon (no [LEVEL] prefix)
Utility:
has_command(cmd)- Check if single command exists (returns 0/1)
Example:
#!/usr/bin/env bash
source "$HOME/.local/shell/formatting.sh"
print_header "Backup Tool" "blue"
print_section "Phase 1: Scanning"
# Visual-only script - no logging needed
for file in *.txt; do
print_success "Scanned: $file"
done
print_header_success "Backup Complete"
error-handling.sh - Robust Error Management¶
Location: ~/.local/shell/error-handling.sh
Purpose: Error trapping, cleanup handlers, and verification utilities
Size: ~280 lines
Dependencies: Sources logging.sh
When to use:
- Scripts that create temporary files/directories
- Download/installation scripts needing retry logic
- Scripts requiring cleanup on exit (success or failure)
- Complex scripts needing stack traces for debugging
- Any script where errors must be trapped and logged
Core Functions:
Cleanup & Traps:
enable_error_traps()- Set up ERR and EXIT signal handlersregister_cleanup(cmd)- Register cleanup commands for exitrun_cleanup()- Execute all registered cleanups
Verification Helpers:
require_commands(cmd1 cmd2...)- Verify commands exist, fatal if missingverify_file(path, desc)- Check file exists and not emptyverify_directory(path, desc)- Check directory existscreate_directory(path, desc)- Create dir with error handling
Advanced Helpers:
run_with_context(desc, cmd...)- Run command with logged descriptiondownload_file_with_retry(url, output, desc, [retries])- Download with retrysafe_move(src, dest, desc)- Move file with verification
Exit & Debug:
exit_success()- Clean exit after running cleanupexit_error(message)- Error exit with cleanupenable_debug()/disable_debug()- Toggle debug mode
Example:
#!/usr/bin/env bash
SHELL_DIR="${SHELL_DIR:-$HOME/.local/shell}"
source "$SHELL_DIR/error-handling.sh"
enable_error_traps
# Register cleanup
TMP_DIR=$(mktemp -d)
register_cleanup "rm -rf $TMP_DIR"
# Verify prerequisites
require_commands curl tar jq
# Download with retry
download_file_with_retry \
"https://example.com/package.tar.gz" \
"$TMP_DIR/package.tar.gz" \
"Package archive" \
3
# Verify and install
verify_file "$TMP_DIR/package.tar.gz" "Downloaded package"
safe_move "$TMP_DIR/binary" "$HOME/.local/bin/binary" "Binary"
# Cleanup runs automatically on exit
exit_success
Decision Guide: log_vs print_¶
Use log_* functions when¶
✅ Script output will be logged to files ✅ Script runs unattended (cron, CI/CD, automated) ✅ Output needs to be parseable by log aggregators ✅ Script is part of installation/update process ✅ You need [LEVEL] prefixes for filtering/monitoring
Examples: install.sh, update.sh, package installers, CI scripts
Use print_* status functions when¶
✅ Script is purely interactive (run by human at terminal) ✅ Visual appeal is priority over parseability ✅ Output will NEVER be piped to log files ✅ Script is a menu system or interactive tool ✅ Logging overhead not needed
Examples: backmeup, interactive menus, demo scripts, dev tools
Use both when¶
✅ Script has both logged sections (log_*) and visual structure (print_header/section) ✅ Most management scripts fall into this category
Example:
source "$HOME/.local/shell/logging.sh"
source "$HOME/.local/shell/formatting.sh"
print_header "System Update" "blue"
print_section "Phase 1: Package Updates"
log_info "Updating apt packages..."
sudo apt update && sudo apt upgrade -y
log_success "Packages updated"
print_section "Phase 2: Cleanup"
log_info "Removing old kernels..."
sudo apt autoremove -y
log_success "Cleanup complete"
print_header_success "Update Complete"
Common Patterns¶
Simple Status Script (logging only)¶
#!/usr/bin/env bash
set -euo pipefail
source "$HOME/.local/shell/logging.sh"
log_info "Processing files..."
# do work
log_success "Processed 42 files"
Visual Interactive Script (formatting only)¶
#!/usr/bin/env bash
set -euo pipefail
source "$HOME/.local/shell/formatting.sh"
print_header "File Manager" "cyan"
print_info "Loading files..."
# show menu
print_success "File selected"
Installation Script (logging + formatting)¶
#!/usr/bin/env bash
set -euo pipefail
DOTFILES_DIR="${DOTFILES_DIR:-$HOME/dotfiles}"
source "$DOTFILES_DIR/platforms/common/.local/shell/logging.sh"
source "$DOTFILES_DIR/platforms/common/.local/shell/formatting.sh"
print_header "Install Package" "blue"
print_section "Phase 1: Download"
log_info "Downloading package..."
# download
log_success "Package downloaded"
print_header_success "Installation Complete"
Complex Script with Error Handling¶
#!/usr/bin/env bash
set -euo pipefail
SHELL_DIR="${SHELL_DIR:-$HOME/.local/shell}"
source "$SHELL_DIR/error-handling.sh"
source "$SHELL_DIR/formatting.sh"
enable_error_traps
# Setup cleanup
TMP_DIR=$(mktemp -d)
register_cleanup "rm -rf $TMP_DIR"
print_header "Build Project" "blue"
# Verify prerequisites
require_commands node npm git
print_section "Phase 1: Dependencies"
run_with_context "Installing dependencies" npm install
print_section "Phase 2: Build"
run_with_context "Building project" npm run build
print_header_success "Build Complete"
exit_success
Function Reference Quick Lookup¶
Logging (with [LEVEL] prefixes)¶
| Function | Purpose | Output | Exit Code |
|---|---|---|---|
log_info |
Informational message | [INFO] ● cyan | - |
log_success |
Success message | [INFO] ✓ green | - |
log_warning |
Warning message | [WARNING] ▲ yellow | - |
log_error |
Error message | [ERROR] ✗ red | - |
log_debug |
Debug message (DEBUG=true) | [DEBUG] gray | - |
log_fatal |
Fatal error | [FATAL] ✗ red | 1 |
die |
Simple fatal error | [ERROR] ✗ red | 1 |
Formatting - Status (no [LEVEL] prefixes)¶
| Function | Purpose | Output | Exit Code |
|---|---|---|---|
print_success |
Visual success | ✓ green | - |
print_error |
Visual error | ✗ red | - |
print_warning |
Visual warning | ▲ yellow | - |
print_info |
Visual info | ● cyan | - |
Formatting - Structure¶
| Function | Purpose | Visual Style |
|---|---|---|
print_header |
Main header | Thick borders (━) |
print_section |
Section header | Thin underline (─) |
print_banner |
Tool banner | Double bars (═) |
print_title |
Page title | Centered, full-width |
Each has color variants and _success/_error/_warning/_info variants with emojis.
Error Handling¶
| Function | Purpose |
|---|---|
enable_error_traps |
Set up ERR/EXIT handlers |
register_cleanup |
Add cleanup command |
require_commands |
Verify multiple commands |
verify_file |
Check file exists/not empty |
verify_directory |
Check directory exists |
create_directory |
Create dir with error handling |
download_file_with_retry |
Download with retry logic |
safe_move |
Move file with verification |
run_with_context |
Run command with logging |
exit_success |
Clean exit with cleanup |
exit_error |
Error exit with cleanup |
Sourcing Patterns¶
From Scripts in Repo (use DOTFILES_DIR)¶
DOTFILES_DIR="${DOTFILES_DIR:-$HOME/dotfiles}"
source "$DOTFILES_DIR/platforms/common/.local/shell/logging.sh"
source "$DOTFILES_DIR/platforms/common/.local/shell/formatting.sh"
From Scripts After Installation (use SHELL_DIR or HOME)¶
SHELL_DIR="${SHELL_DIR:-$HOME/.local/shell}"
source "$SHELL_DIR/logging.sh"
source "$SHELL_DIR/formatting.sh"
source "$SHELL_DIR/error-handling.sh"
From Interactive Shell (already sourced in .zshrc)¶
Functions are available directly in interactive shells - no need to source.
Best Practices¶
- Always use log_* for installation/update scripts - They need parseability
- Always use print_* for purely visual tools - No logging overhead
- Source error-handling.sh for complex scripts - Automatic cleanup is valuable
- Use file:line in log_error/log_fatal - Makes debugging easier
- Register cleanup early - Before creating temp files
- Prefer log_fatal over die when you have file:line info
- Use print_header/section for visual structure - Even in logged scripts
- Don't mix print_success with log_info - Pick one style per script
See Also¶
platforms/common/.local/shell/colors.sh- Color definitions- Symlinks Manager - Symlinks manager documentation