Skip to main content

Overview

bash::framehead follows a modular architecture that compiles into a single sourceable file. The framework consists of 16 independent modules organized in the src/ directory, each providing a focused set of functionality following the module::function naming convention.

Design principles

The framework is built around several core principles:

Single file distribution

Everything compiles into one sourceable file. No PATH gymnastics, no install scripts, no package managers.

Modular by design

Modules have minimal coupling. Mix and match freely — remove what you don’t need.

Graceful degradation

Functions check for required tools at runtime and fail cleanly with helpful messages.

No magic

No global state mutation, no surprise side effects. Functions take input, return output.

Directory structure

The project follows a clean, logical structure:
bash-framehead/
├── main.sh               # Entry point — compile, test, stat
├── src/
   ├── runtime.sh        # Core runtime detection (required)
   ├── string.sh         # String manipulation (933 lines)
   ├── math.sh           # Integer and float math (841 lines)
   ├── hardware.sh       # Hardware introspection (773 lines)
   ├── timedate.sh       # Date/time operations (711 lines)
   ├── fs.sh             # Filesystem operations (523 lines)
   ├── process.sh        # Process management (488 lines)
   ├── net.sh            # Networking utilities (441 lines)
   ├── array.sh          # Array operations (438 lines)
   ├── random.sh         # RNG implementations (401 lines)
   ├── terminal.sh       # Terminal control (377 lines)
   ├── hash.sh           # Hashing algorithms (367 lines)
   ├── runtime.sh        # Runtime detection (331 lines)
   ├── colour.sh         # ANSI color utilities (321 lines)
   ├── device.sh         # Block device ops (292 lines)
   ├── git.sh            # Git operations (215 lines)
   └── pm.sh             # Package manager abstraction (113 lines)
└── compiled.sh           # Generated output

Module dependencies

Most modules are designed to be independent, with one critical exception:
runtime.sh is required — all other modules depend on it for environment detection via functions like runtime::has_command and runtime::is_minimum_bash.
Modules declare their dependencies at the top:
main.sh:3-6
#!/usr/bin/env bash
# array.sh — bash-frameheader array lib
# Requires: runtime.sh (runtime::is_minimum_bash)
main.sh:3-6
#!/usr/bin/env bash
# math.sh — bash-frameheader math lib  
# Requires: runtime.sh (runtime::has_command)
This minimal coupling means you can remove modules you don’t need (except runtime.sh) and the framework will still compile and function correctly.

Compilation flow

The compilation process is handled by the compile_files() function in main.sh:
1

Validation

Verify the src/ directory exists and contains .sh files.
main.sh:8-23
# Validate src directory exists
if [[ ! -d "$src_dir" ]]; then
    echo "Error: src directory not found: $src_dir" >&2
    return 1
fi

# Collect .sh files upfront
local -a files=()
for f in "$src_dir"/*.sh; do
    [[ -f "$f" ]] && files+=("$f")
done
2

ShellCheck analysis

Run ShellCheck on each module to detect errors, warnings, and style issues.
main.sh:44-52
if $has_shellcheck; then
    local sc_out
    sc_out=$(shellcheck --format=gcc "$func_file" 2>/dev/null)
    err_file=$(echo "$sc_out"  | grep -c ': error:')
    warn_file=$(echo "$sc_out" | grep -c ': warning:')
    info_file=$(echo "$sc_out" | grep -c ': note:')

    shellcheck --color=auto --format=tty "$func_file" 2>/dev/null || true
fi
3

File concatenation

Concatenate all module files, stripping shebangs from all files except the first.
main.sh:66-75
while IFS= read -r line; do
    # Strip shebang from all but the first file
    if (( i > 0 && i_line == 0 )); then
        (( i_line++ ))
        [[ "$line" =~ ^#! ]] && continue
    fi
    printf '%s\n' "$line" >> "$output_file"
    (( i_line++ ))
done < "$func_file"
4

Output finalization

Make the output file executable and report compilation statistics.
main.sh:88-96
chmod +x "$output_file" 2>/dev/null

echo "Compiled $i file(s) to $output_file${final_issue_str}"

Runtime initialization

When you source the compiled file, all ~785 functions are loaded into the current shell’s namespace. The framework includes a statistics function to measure load performance:
main.sh:109-118
echo "=== Testing load time in fresh shell ==="
command time -f "Real: %e s, User: %U s, Sys: %S s" \
  bash -c "source $file"

echo "=== Function count by module ==="
(
  source $file
  declare -F | awk -F'::' '{print $1}' | sort | uniq -c | sort -rn
  echo "$(declare -F | wc -l) total functions loaded"
)
Load time is typically under 0.1 seconds on modern hardware, making the framework suitable for both interactive scripts and automation.

Function organization

Each module groups related functions by category. For example, string.sh organizes its 115 functions into:
  • Inspection — length, contains, validation checks
  • Case conversion — upper, lower, capitalize, title case
  • Transformation — trim, pad, truncate, repeat
  • Encoding — base64, base32, URL, MD5, SHA256
  • Case system — conversions between snake_case, camelCase, kebab-case, etc.
This organization makes the codebase maintainable and predictable despite its size.

Pure Bash philosophy

The framework prioritizes pure Bash implementations where practical:
src/string.sh:93-95
# Convert to uppercase
string::upper() {
  echo "${1^^}"
}
When external tools are required (like bc for floating point math), functions check availability first:
src/math.sh:37-44
math::bc() {
    local expr="$1" scale="${2:-$MATH_SCALE}"
    if ! math::has_bc; then
        echo "math::bc: requires bc (GNU coreutils)" >&2
        return 1
    fi
    echo "scale=${scale}; ${expr}" | bc -l
}
This ensures scripts fail gracefully with actionable error messages rather than cryptic command-not-found errors.

Testing infrastructure

The framework includes a comprehensive test suite in the tester() function with custom test helpers:
main.sh:175-189
_test() {
    local name="$1" expected="$2" actual="$3"
    local clean=true
    _check_stderr || clean=false
    if [[ "$actual" == "$expected" ]] && $clean; then
        echo -e "  $PASS  $name"
        (( passed++ ))
    else
        echo -e "  $FAIL  $name"
        [[ "$actual" != "$expected" ]] && \
            echo "        expected: $expected" && \
            echo "        actual:   $actual"
        (( failed++ ))
    fi
}
Tests cover all 785 functions with equality checks, substring matching, and non-empty validation.

Next steps

Module system

Explore the 16 available modules and their functions

Compilation process

Learn how to compile and customize your build

Naming conventions

Master the module::function pattern

Quick start

Get started with your first script

Build docs developers (and LLMs) love