The module::function pattern
bash::framehead uses a strict module::function naming convention for all 785 functions. This pattern provides namespace isolation, predictable discovery, and self-documenting code.
Why double colons?
The :: delimiter is valid in Bash function names and serves as a clear visual separator:
string::upper "hello" # Immediately clear: string module, upper function
math::factorial 5 # Math module, factorial function
fs::path::basename "/foo" # Filesystem module, path subgroup, basename function
Unlike many languages, Bash doesn’t have true namespaces. The :: convention is purely visual but highly effective for organizing 785 functions.
Convention structure
All function names follow this hierarchy:
module::function
module::subgroup::function
module::function::variant
module::subgroup::function::variant
Examples from the source
Simple module::function:
string::length () {
echo "${ # 1 }"
}
Module with subgroup:
fs::path::basename () # Filesystem → path operations → basename
fs::path::dirname () # Filesystem → path operations → dirname
fs::path::extension () # Filesystem → path operations → extension
Function variants:
# Modern Bash 4+ version
string::upper () {
echo " ${1 ^^ } "
}
# Bash 3 compatible version
string::upper::legacy () {
echo " $1 " | tr '[:lower:]' '[:upper:]'
}
Subgroup organization
Complex modules use subgroups to organize related functions:
Filesystem paths
fs::path::basename # Extract filename from path
fs::path::dirname # Extract directory from path
fs::path::extension # Get file extension
fs::path::stem # Get filename without extension
fs::path::join # Join path components
fs::path::absolute # Convert to absolute path
fs::path::relative # Get relative path between two paths
Filesystem permissions
fs::permissions # Get numeric permissions (e.g., 755)
fs::permissions::symbolic # Get symbolic permissions (e.g., rwxr-xr-x)
Array sorting
array::sort # Sort alphabetically ascending
array::sort::reverse # Sort alphabetically descending
array::sort::numeric # Sort numerically ascending
array::sort::numeric_reverse # Sort numerically descending
Color depth levels
colour::fg::red # 4-bit ANSI foreground red
colour::bg::blue # 4-bit ANSI background blue
colour::fg::256 # 8-bit foreground color by index
colour::bg::rgb # 24-bit background color by RGB
Subgroups are discoverable via shell completion. Type fs::path:: and press Tab to see all path-related functions.
Variant conventions
Variants handle alternative implementations or optional dependencies:
Legacy compatibility
Bash 3 compatible versions for older systems:
string::upper () # Bash 4+ using ${var^^}
string::upper::legacy () # Bash 3+ using tr command
string::lower () # Bash 4+ using ${var,,}
string::lower::legacy () # Bash 3+ using tr command
string::base64_encode () # Requires base64 command
string::base64_encode::pure () # Pure Bash implementation (slower)
string::base64_decode () # Requires base64 command
string::base64_decode::pure () # Pure Bash implementation (slower)
fs::size () # Bytes as integer
fs::size::human () # Human-readable (e.g., "2.3M")
fs::modified () # Unix timestamp
fs::modified::human () # Human-readable date string
Discovery and completion
The naming convention enables powerful shell completion:
# List all string functions
declare -F | grep '^string::'
# List all path functions
declare -F | grep '^fs::path::'
# Count functions per module
declare -F | awk -F '::' '{print $1}' | sort | uniq -c
Example output:
=== Function count by module ===
115 string
79 fs
74 timedate
74 terminal
65 colour
...
785 total functions loaded
Naming consistency
All functions follow consistent verb patterns:
Boolean predicates
Functions that return exit codes use is_, has_, or question form:
runtime::is_terminal () # Exit 0 if true, 1 if false
runtime::is_interactive ()
runtime::has_command bc
math::has_bc
array::is_empty
string::is_integer
string::is_empty
fs::is_file
fs::is_dir
fs::is_symlink
Usage:
if runtime::is_terminal ; then
echo "Running in a terminal"
fi
if ! string::is_empty " $var " ; then
process::value " $var "
fi
Action verbs
Functions that perform operations use clear verbs:
string::upper # Convert → upper
string::trim # Remove whitespace → trim
array::reverse # Reverse order → reverse
array::sort # Sort elements → sort
fs::read # Read file → read
fs::write # Write file → write
hash ::verify # Verify hash → verify
process::kill # Kill process → kill
Getters
Functions that retrieve information use descriptive nouns:
string::length # Get length
array::first # Get first element
array::last # Get last element
fs::size # Get file size
fs::owner # Get file owner
runtime::os # Get operating system
runtime::arch # Get architecture
Testing conventions
The test suite in main.sh follows the same patterns:
_test "string::upper" "HELLO" "$( string::upper hello)"
_test "string::lower" "hello" "$( string::lower HELLO)"
_test "string::length" "5" "$( string::length hello)"
_test "string::contains (true)" "0" "$( string::contains hello ell; echo $? )"
_test "string::contains (false)" "1" "$( string::contains hello xyz; echo $? )"
_test "string::reverse" "olleh" "$( string::reverse hello)"
_test "string::trim" "hello" "$( string::trim " hello ")"
_test "string::repeat" "aaa" "$( string::repeat a 3 )"
_test "string::is_integer (true)" "0" "$( string::is_integer 42 ; echo $? )"
_test "string::is_integer (false)" "1" "$( string::is_integer abc; echo $? )"
Test names mirror function names with result indicators in parentheses.
Documentation alignment
Function documentation follows the same hierarchy:
# String length
# Usage: string::length str
string::length () {
echo "${ # 1 }"
}
# Check if string contains substring
# Usage: string::contains haystack needle
string::contains () {
[[ " $1 " == * " $2 " * ]]
}
The wiki generator parses these comments to create structured API documentation automatically.
Reserved patterns
Certain patterns are reserved for framework internals:
Double underscores
Private helper functions use __ prefix:
_test () # Test suite helper
_check_stderr () # Internal test utility
_mark_tested () # Test tracking helper
User scripts should never define functions starting with _ to avoid conflicts with internal helpers.
Module names
The following module names are reserved and define the public API:
string
array
math
fs
runtime
hash
random
process
net
git
timedate
terminal
colour
hardware
device
pm
Adding custom functions
When extending the framework, follow the established patterns:
# Good: Clear module, subgroup, and function
mymodule::api::fetch () {
curl -s " $1 "
}
mymodule::api::post () {
curl -s -X POST " $1 " -d " $2 "
}
# Bad: No module prefix (pollutes global namespace)
fetch_api () {
curl -s " $1 "
}
# Bad: Inconsistent delimiter
mymodule_api_fetch () {
curl -s " $1 "
}
Function signature patterns
Consistent parameter ordering improves usability:
Target-first pattern
Operations take the target/subject as the first parameter:
string::upper "hello" # Subject: string
string::contains "haystack" "needle" # Subject: haystack
array::contains element "${ array [ @ ]}" # Subject: array elements
fs::read "/path/to/file" # Subject: file
hash ::md5 "content" # Subject: content
Options-last pattern
Optional parameters come last with sensible defaults:
math::bc "22/7" 2 # precision (default: 10)
string::truncate "hello" 4 # length (ellipsis added)
string::pad_left "hi" 5 # width (default char: space)
array::chunk "${ items [ @ ]}" 3 # chunk size
Discovering functions
Use shell introspection to explore the API:
# All functions
declare -F
# Functions from one module
declare -F | grep '^declare -f string::'
# Functions in a subgroup
declare -F | grep '^declare -f fs::path::'
# Count by module
declare -F | awk '{print $3}' | awk -F '::' '{print $1}' | sort | uniq -c
Next steps
Architecture Understand the framework structure
Module system Explore the 16 available modules
Compilation Learn how to build custom distributions
API Reference Browse all 785 functions