A collection of comprehensive shell utility libraries providing common functions and tools for bash scripts.
Three Section:
- Bash Utility Libraries
- Library 1: sh-globals.sh
- Key Features
- Getting Started
- Initialization
- Function Reference
- 1. Color and Formatting
- 2. Message Functions
- 3. Robust Logging System
- 4. Advanced String Operations
- 5. Array Functions
- 6. File & Directory Management
- 7. User Interaction Functions
- 8. System and Environment Functions
- 9. OS Detection Functions
- 10. Date & Time Functions
- 11. Networking Functions
- 12. Script Lock Functions
- 13. Error Handling Functions
- 14. Dependency Management
- 15. Number Formatting Functions
- 16. Path Navigation Functions
- Advanced Usage Patterns
- Tips for Effective Use of sh-globals.sh
- Library 2: param_handler.sh
- Library 3: tmux_utils1.sh
- Combined Usage Example
This repository contains multiple utility libraries designed to simplify shell scripting:
- sh-globals.sh: A comprehensive shell utility library with color definitions, string operations, file handling, error management, and more.
- param_handler.sh: A lightweight Bash library for handling both named and positional command-line parameters in shell scripts.
- tmux_utils1.sh: A utility library for managing tmux sessions from shell scripts, providing multiple approaches for executing scripts in tmux panes with variable sharing between the host script and tmux sessions.
These libraries aim to make shell scripting more robust, maintainable, and easier to implement.
- Download the required files:
# Clone the repository
git clone https://github.com/yourusername/Util-Sh.git
cd Util-Sh
- Make the scripts executable:
chmod +x sh-globals.sh param_handler.sh tmux_utils1.sh
- Source the libraries in your script:
#!/usr/bin/env bash
source "$(dirname "$0")/sh-globals.sh"
source "$(dirname "$0")/param_handler.sh"
source "$(dirname "$0")/tmux_utils1.sh"
# Initialize libraries
sh-globals_init "$@"
The param_handler.sh
library depends on getoptions, a powerful command-line argument parser for shell scripts.
- Repository: ko1nksm/getoptions
- License: Creative Commons Zero v1.0 Universal
- Version: v3.3.2 (included in this project)
sh-globals.sh
is a comprehensive utility library that enhances your shell scripts with a wide range of functionality through carefully crafted functions, consistent error handling, and standardized output formatting.
- Terminal Output Enhancement: Rich color and formatting options for better user experience
- Robust Logging System: Multi-level logging with file and console output
- Advanced String Operations: Comprehensive string manipulation functions
- File System Tools: Safe file operations with validation and error handling
- Error Management: Error trapping, cleanup, and stack traces
- User Interaction Helpers: User prompts, confirmations, and secure input
- System Information: OS detection, environment management, and user/host information
- Path Manipulation: Advanced path operations and source file management
- Temporary Resource Management: Auto-cleanup of temporary files and directories
- Process Control: Script locking to prevent concurrent execution
- Human-Readable Formatting: Number and date formatting for better readability
#!/usr/bin/env bash
# Source the library
source "$(dirname "$0")/sh-globals.sh"
# Initialize with your script's arguments (IMPORTANT)
sh-globals_init "$@"
# Now you can use all the library functions
msg_header "Welcome to My Script"
msg_info "Running as user: $(get_current_user)"
msg_info "Operating system: $(get_os)"
# Check for required dependencies
if ! check_dependencies curl jq; then
msg_error "Missing required tools"
exit 1
fi
# Create a lock to prevent multiple instances
if ! create_lock; then
msg_error "Another instance is already running"
exit 1
fi
# Script logic follows...
Function | Description |
---|---|
sh-globals_init [args...] |
Initialize the shell globals. |
It is crucial to call sh-globals_init "$@"
at the beginning of your script after sourcing the library. This function performs several essential setup tasks:
- Sets up trap handlers for errors (
ERR
) and script exit (EXIT
,HUP
,INT
,QUIT
,TERM
). - Enables
pipefail
so that pipelines return a failure status if any command fails. - Initializes common flag variables like
DEBUG
,VERBOSE
,QUIET
,FORCE
. - Parses common command-line flags (
--debug
,--verbose
,--quiet
,--force
,--help
,--version
) from the script's arguments ("$@"
). - Sets up the mechanism for automatic cleanup of temporary files and directories created via
create_temp_file
andcreate_temp_dir
. - Ensures the script lock (if created using
create_lock
) is released on exit.
Example:
# Source the utilities and initialize
source "$(dirname "$0")/sh-globals.sh"
sh-globals_init "$@"
echo "Shell utilities initialized"
# Now other functions can be used
log_info "Script starting"
# Check flags parsed by sh-globals_init
if [[ "$DEBUG" -eq 1 ]]; then
msg_debug "Debug mode is ON"
fi
if [[ "$VERBOSE" -eq 1 ]]; then
msg_info "Verbose mode is ON"
fi
Provides constants for adding colors and formatting to terminal output.
Variable | Description |
---|---|
BLACK , RED , GREEN , YELLOW , BLUE , MAGENTA , CYAN , WHITE , GRAY |
Text colors |
BG_BLACK , BG_RED , BG_GREEN , BG_YELLOW , BG_BLUE , BG_MAGENTA , BG_CYAN , BG_WHITE |
Background colors |
BOLD , DIM , UNDERLINE , BLINK , REVERSE , HIDDEN |
Text formatting |
NC |
Reset color/format |
Example:
# Example of using colors
echo -e "${RED}Error:${NC} Something went wrong"
echo -e "${GREEN}Success:${NC} Operation completed"
echo -e "${BOLD}${BLUE}Important:${NC} Read this carefully"
echo -e "${YELLOW}Warning:${BOLD} Important note${NC}"
echo -e "${BG_BLUE}${WHITE}Highlighted information${NC}"
# Output:
# Error: Something went wrong (in red)
# Success: Operation completed (in green)
# Important: Read this carefully (in bold blue)
# Warning: Important note (in yellow, note is bold)
# Highlighted information (white text on blue background)
Modern formatted message functions for clear, consistent terminal output. These functions handle colorization and standard prefixes automatically.
Function | Description | Parameters | Returns |
---|---|---|---|
msg [message...] |
Display a plain message | message... |
None |
msg_info [message...] |
Display an informational message (blue) | message... |
None |
msg_success [message...] |
Display a success message (green) | message... |
None |
msg_warning [message...] |
Display a warning message (yellow) to stderr | message... |
None |
msg_error [message...] |
Display an error message (red) to stderr | message... |
None |
msg_highlight [message...] |
Display a highlighted message (cyan) | message... |
None |
msg_header [message...] |
Display a header message (bold, magenta) | message... |
None |
msg_section [text] [width=80] [char=] |
Display a section divider with text | [text] [width] [char] |
None |
msg_subtle [message...] |
Display a subtle/dim message (gray) | message... |
None |
msg_color [message] [color] |
Display a message with custom color | message color |
None |
msg_step [step] [total] [description] |
Display a step or progress message | step total description |
None |
msg_debug [message...] |
Display debug message (cyan, if DEBUG=1) | message... |
None |
Example:
# Basic messages
msg "Standard message"
msg_info "Informational message"
msg_success "Success message"
msg_warning "Warning message"
msg_error "Error message"
msg_highlight "Highlighted message"
msg_header "SECTION HEADER"
msg_subtle "This is less important."
# Section dividers
msg_section "Configuration" 60 "-" # Centered text with dashes
msg_section "" 80 "*" # Just a line of asterisks
# Custom color
msg_color "This is a custom colored message" "$MAGENTA"
# Progress steps
msg_step 1 5 "Downloading resources"
msg_step 2 5 "Extracting files"
# Debug message (displays only when DEBUG=1)
DEBUG=1
msg_debug "Debug information here"
Multi-level logging with optional timestamping and file output. Useful for tracking script execution over time.
Function | Description | Parameters | Returns |
---|---|---|---|
log_init [log_file] [save_to_file=1] |
Initialize logging system (optional file path & toggle) | [file_path] [save_to_file=1] |
None |
log_info [message...] |
Log informational message | message... |
None |
log_warn [message...] |
Log warning message | message... |
None |
log_error [message...] |
Log error message | message... |
None |
log_debug [message...] |
Log debug message (only if DEBUG=1) | message... |
None |
log_success [message...] |
Log success message | message... |
None |
log_with_timestamp [level] [message...] |
Log with custom level and timestamp | level message... |
None |
Example:
# Initialize logging (optionally to file)
log_init "/var/log/myscript.log" # Log to specified file and console
# log_init # Log to ./script_name.log and console
# log_init "" 0 # Log only to console
# Set debug mode (optional)
DEBUG=1
# Log messages at different levels
log_info "Operation started"
log_warn "Resource usage high"
log_error "Failed to connect to server"
log_debug "Variable state: value=example" # Only logged if DEBUG=1
log_success "Backup completed successfully"
# Custom timestamp logging
log_with_timestamp "CUSTOM" "Special event occurred"
Function | Description | Parameters | Returns |
---|---|---|---|
str_contains [string] [substring] |
Check if string contains substring | string substring |
Boolean (exit code) |
str_starts_with [string] [prefix] |
Check if string starts with prefix | string prefix |
Boolean (exit code) |
str_ends_with [string] [suffix] |
Check if string ends with suffix | string suffix |
Boolean (exit code) |
str_trim [string] |
Trim whitespace from string ends | string |
Trimmed string |
str_to_upper [string] |
Convert string to uppercase | string |
Uppercase string |
str_to_lower [string] |
Convert string to lowercase | string |
Lowercase string |
str_length [string] |
Get string length | string |
Length (integer) |
str_replace [string] [search] [replace] |
Replace substring in string | string search replace |
Modified string |
Example:
# String operations
name=" John Doe "
filename="log-backup-2023.tar.gz.bak"
# String tests (return 0 for true, 1 for false)
if str_contains "$name" "John"; then
echo "'$name' contains 'John'" # Prints
fi
if str_starts_with "$filename" "log-"; then
echo "'$filename' starts with 'log-'" # Prints
fi
if str_ends_with "$filename" ".bak"; then
echo "'$filename' ends with '.bak'" # Prints
fi
# String transformations
trimmed=$(str_trim "$name")
echo "Trimmed: '$trimmed'" # Output: 'John Doe'
upper=$(str_to_upper "$name")
echo "Uppercase: '$upper'" # Output: ' JOHN DOE '
lower=$(str_to_lower "$name")
echo "Lowercase: '$lower'" # Output: ' john doe '
length=$(str_length "$trimmed")
echo "Length of trimmed: $length" # Output: 8
replaced=$(str_replace "$name" "John" "Jane")
echo "Replaced: '$replaced'" # Output: ' Jane Doe '
Function | Description | Parameters | Returns |
---|---|---|---|
array_contains [element] [array...] |
Check if array contains element | element array... |
Boolean (exit code) |
array_join [delimiter] [array...] |
Join array elements with delimiter | delimiter array... |
Joined string |
array_length [array_name] |
Get array length (pass name only) | array_name |
Length (integer) |
Example:
# Define an array
fruits=("apple" "banana" "orange" "grape")
# Check if array contains element
if array_contains "banana" "${fruits[@]}"; then
echo "Array contains banana" # Prints
fi
# Join array elements
joined=$(array_join ", " "${fruits[@]}")
echo "Joined: $joined" # Output: apple, banana, orange, grape
# Get array length (pass the array name as a string)
declare -a colors=("red" "green" "blue")
len=$(array_length colors)
echo "Colors array length: $len" # Output: 3
Includes functions for safe file operations, checks, and temporary resource management.
Function | Description | Parameters | Returns |
---|---|---|---|
command_exists [command] |
Check if command exists in PATH | command |
Boolean (exit code) |
safe_mkdir [directory] |
Create directory if it doesn't exist | directory |
None |
file_exists [path] |
Check if file exists and is readable | path |
Boolean (exit code) |
dir_exists [path] |
Check if directory exists | path |
Boolean (exit code) |
file_size [path] |
Get file size in bytes | path |
Size (bytes) |
safe_copy [src] [dst] |
Copy file with verification | src dst |
Boolean (exit code) |
create_temp_file [template=tmp.XXXXXXXXXX] |
Create a temp file (auto-cleaned) | [template] |
Temp file path |
create_temp_dir [template=tmp.XXXXXXXXXX] |
Create a temp directory (auto-cleaned) | [template] |
Temp dir path |
wait_for_file [file] [timeout=30] [interval=1] |
Wait for a file to exist | file [timeout] [interval] |
Boolean (exit code) |
get_file_extension [filename] |
Get file extension (without dot) | filename |
Extension string |
get_file_basename [filename] |
Get filename without extension | filename |
Base filename |
cleanup_temp |
Manually clean up temp files/dirs | None | None |
Example:
# Check prerequisites
if ! command_exists "jq"; then
msg_error "jq command not found. Please install jq."
exit 1
fi
# Safe directory creation
safe_mkdir "/var/data/app/logs"
# Temporary file handling (auto-cleaned on exit)
temp_data=$(create_temp_file "data_proc_XXXX")
temp_dir=$(create_temp_dir "results_XXXX")
msg_info "Using temp file $temp_data and temp dir $temp_dir"
Functions to prompt the user for input, confirmation, and validated values.
Function | Description | Parameters | Returns |
---|---|---|---|
confirm [prompt="Are you sure?"] [default=n] |
Confirm prompt (y/n) | [prompt] [default=y|n] |
Boolean (exit code) |
confirm_enter_esc [prompt] |
Simple Enter to confirm, Esc to cancel | [prompt] |
Boolean (exit code) |
prompt_input [prompt] [default] |
Prompt for input with optional default | prompt [default] |
User input string |
prompt_password [prompt="Password:"] |
Prompt for password (hidden input) | [prompt] |
Password string |
get_number [prompt] [default] [min] [max] |
Get a validated numeric input | [prompt] [default] [min] [max] |
Number |
get_string [prompt] [default] [pattern] [error_msg] |
Get string with optional regex validation | [prompt] [default] [pattern] [error_msg] |
String |
get_path [prompt] [default] [type] [must_exist=0] |
Get file/directory path with validation | [prompt] [default] [type] [must_exist] |
Path string |
get_value [prompt] [default] [validator_func] [error_msg] |
Get value with custom validation function | [prompt] [default] [validator] [error_msg] |
Validated value |
Example:
# Simple confirmation (returns 0 for yes, 1 for no)
if confirm "Delete all temporary files?" "n"; then
msg_info "Deleting files..."
else
msg_info "Deletion cancelled."
fi
# Simplified Enter/Escape confirmation
if confirm_enter_esc "Press Enter to continue, Esc to cancel:"; then
msg_success "Continuing with operation..."
else
msg_warning "Operation cancelled."
fi
# Input with default value
name=$(prompt_input "Enter your name" "guest")
msg_info "Hello, $name!"
# Validated numeric input
port=$(get_number "Enter server port" "8080" "1" "65535")
msg_info "Using port: $port"
Function | Description | Parameters | Returns |
---|---|---|---|
env_or_default [var_name] [default] |
Get environment variable or default | var_name [default] |
Value string |
is_root |
Check if script is run as root | None | Boolean (exit code) |
require_root |
Exit script if not running as root | None | None (or exits) |
parse_flags [args...] |
Parse common flags (used by init) | args... |
None (sets vars) |
get_current_user |
Get current username | None | Username string |
get_hostname |
Get system hostname | None | Hostname string |
Example:
# Environment variables
api_key=$(env_or_default "API_KEY" "default-key")
log_level=$(env_or_default "LOG_LEVEL" "INFO")
# Privilege checks
if ! is_root; then
msg_warning "This script ideally runs as root, but proceeding."
fi
Function | Description | Parameters | Returns |
---|---|---|---|
get_os |
Get OS type (linux, mac, windows) | None | OS string |
get_linux_distro |
Get Linux distribution name (if OS=linux) | None | Distro name string |
get_arch |
Get processor architecture | None | Arch string (amd64, arm64...) |
is_in_container |
Check if running in a container | None | Boolean (exit code) |
Example:
# Detect OS information
os_type=$(get_os)
arch=$(get_arch)
msg_info "OS Type: $os_type"
msg_info "Architecture: $arch"
if [[ "$os_type" == "linux" ]]; then
distro=$(get_linux_distro)
msg_info "Linux Distribution: $distro" # e.g., ubuntu, debian, centos
fi
Function | Description | Parameters | Returns |
---|---|---|---|
get_timestamp |
Get current timestamp (Unix epoch seconds) | None | Timestamp (integer) |
format_date [format=%Y-%m-%d] [timestamp=now] |
Format date/time using strftime |
[format] [timestamp] |
Formatted date string |
time_diff_human [start] [end=now] |
Human-readable time difference | start_ts [end_ts] |
Formatted time string |
Example:
# Record start time
start_time=$(get_timestamp)
msg_info "Operation started at: $start_time"
# Format dates consistently
today=$(format_date "%Y-%m-%d") # Default format
log_ts=$(format_date "%Y%m%d_%H%M%S")
iso_ts=$(format_date "%Y-%m-%dT%H:%M:%SZ") # ISO 8601 format in UTC
# Do some work...
sleep 3
# Get elapsed time in human-readable format
end_time=$(get_timestamp)
elapsed=$(time_diff_human "$start_time" "$end_time") # e.g., "3s"
msg_info "Operation completed in $elapsed"
Function | Description | Parameters | Returns |
---|---|---|---|
is_url_reachable [url] [timeout=5] |
Check if URL is reachable (HEAD/GET) | url [timeout] |
Boolean (exit code) |
get_external_ip |
Get external/public IP address | None | IP address string |
is_port_open [host] [port] [timeout=2] |
Check if TCP port is open on host | host port [timeout] |
Boolean (exit code) |
Example:
# Check connectivity
if is_url_reachable "https://api.example.com" 3; then
msg_success "API endpoint is reachable."
else
msg_error "Cannot reach API endpoint."
fi
# Get public IP
my_ip=$(get_external_ip)
if [[ -n "$my_ip" ]]; then
msg_info "My external IP address: $my_ip"
fi
Prevents multiple instances of the script from running simultaneously using a lock file.
Function | Description | Parameters | Returns |
---|---|---|---|
create_lock [lock_file] |
Create lock file (fails if valid lock exists) | [lock_file] |
Boolean (exit code) |
release_lock |
Release the lock file (usually done automatically) | None | None |
Example:
# Attempt to create the lock
if ! create_lock; then
msg_error "Another instance is already running."
exit 1
fi
msg_success "Lock acquired. Running exclusively."
# Lock will be released automatically on exit.
Function | Description | Parameters | Returns |
---|---|---|---|
print_stack_trace |
Print the current function call stack | None | None |
error_handler [exit_code] [line_number] |
Default ERR trap handler (logs, cleans up) | exit_code line_number |
None |
setup_traps |
Setup ERR and EXIT traps (used by init) | None | None |
Function | Description | Parameters | Returns |
---|---|---|---|
check_dependencies [cmd...] |
Check if required commands exist | commands... |
Boolean (exit code) |
Example:
# Check for essential tools at the start of the script
if ! check_dependencies git docker kubectl helm; then
msg_error "Please install the missing tools and try again."
exit 1
fi
Function | Description | Parameters | Returns |
---|---|---|---|
format_si_number [number] [precision=1] |
Format number with SI prefixes (K, M, G, T, P, m, ÎĽ, n) | number [precision] |
Formatted string |
format_bytes [bytes] [precision=1] |
Format bytes to human-readable size (KB, MB, GB, TB) | bytes [precision] |
Formatted string |
Example:
# Format numbers with SI prefixes
users=8543210
formatted_users=$(format_si_number "$users") # "8.5M"
# Format bytes with appropriate units
file_size_bytes=2684354560
formatted_size=$(format_bytes "$file_size_bytes") # "2.5GB"
Function | Description | Parameters | Returns |
---|---|---|---|
get_script_dir |
Get the directory containing the script | None | Script directory path |
get_script_name |
Get the filename of the script | None | Script filename |
get_script_path |
Get the full path to the script | None | Full script path |
get_line_number |
Get the current line number in the script | None | Current line number |
get_parent_dir [path=pwd] |
Get parent directory of a path | [path] |
Parent directory path |
get_parent_dir_n [path=pwd] [levels=1] |
Get parent directory N levels up | [path] [levels] |
Path N levels up |
path_relative_to_script [relative_path] |
Make path absolute, relative to script dir | relative_path |
Absolute path |
to_absolute_path [path] [base_dir=pwd] |
Convert relative path to absolute | path [base_dir] |
Absolute path |
source_relative [relative_path] |
Source file relative to calling script | relative_path |
Boolean (exit code) |
source_with_fallbacks [filename] [paths...] |
Source file with fallback locations | filename [fallback_paths...] |
Boolean (exit code) |
parent_path [levels=1] |
Create path string like ../../ |
[levels] |
Path string |
Example:
# Get script location information
script_dir=$(get_script_dir)
script_name=$(get_script_name)
script_path=$(get_script_path)
log_info "Running script: $script_name in $script_dir"
#!/usr/bin/env bash
source "$(dirname "$0")/sh-globals.sh"
sh-globals_init "$@"
# Initialize logging
log_init "/var/log/myapp.log"
# Function that may fail
perform_operation() {
local path="$1"
if [[ ! -d "$path" ]]; then
# This will trigger the error handler due to set -e
return 1
fi
# Successful operation
return 0
}
# Main processing logic
main() {
log_info "Script started"
# Create a lock
if ! create_lock; then
log_error "Another instance is already running"
exit 1
fi
# Perform operations
if ! perform_operation "/nonexistent/path"; then
log_error "Operation failed"
# No need to exit, cleanup is handled automatically
return 1
fi
log_success "Script completed successfully"
}
# Run main function
main
#!/usr/bin/env bash
source "$(dirname "$0")/sh-globals.sh"
sh-globals_init "$@"
process_data() {
# Create temporary resources
local temp_dir=$(create_temp_dir)
local temp_file1=$(create_temp_file)
local temp_file2=$(create_temp_file)
# Download data
wget -q "https://example.com/data.csv" -O "$temp_file1"
# Process data
sort "$temp_file1" > "$temp_file2"
cut -d, -f1,2 "$temp_file2" > "$temp_dir/result.csv"
# Files will be automatically cleaned up on script exit
echo "$temp_dir/result.csv"
}
# Main script
result_file=$(process_data)
msg_success "Data processed and saved to $result_file"
cat "$result_file"
- Always Initialize: Call
sh-globals_init "$@"
at the beginning of your script to set up traps and other features. - Prefer msg_ over echo*: Use
msg_info
,msg_error
, etc. instead of direct echo commands for consistent, colorized output. - Use log_ for persistent logs*: When you need to track script execution over time, initialize logging with
log_init
and use thelog_*
functions. - Let error handling work for you: The library sets up error trapping automatically. Let errors propagate naturally and rely on the cleanup functions.
- Leverage temporary resource creation: Use
create_temp_file
andcreate_temp_dir
to get auto-cleaned temporary resources. - Build on validation functions: Compose complex validation by combining the
get_*
input functions with custom validators.
The param_handler.sh
library simplifies handling both named and positional command-line parameters in shell scripts.
- Handle both named (
--option value
) and positional parameters in a single script - Automatic parameter registration and management
- Built-in help message generation
- Color-coded output for better readability
- Parameter value retrieval and state checking
- Multiple display formats
- JSON export capability
- Environment variable export with prefix support
- Required parameters with validation
- Parameter validation using custom functions
#!/usr/bin/bash
source param_handler.sh
# Define parameters in an indexed array
# Format: "internal_name:VARIABLE_NAME[:option_name]:Description[:REQUIRE][:getter_func]"
declare -a PARAMS=(
# Basic format: internal_name:VARIABLE_NAME:Description
"name:NAME:Person's name" # Creates $NAME and --name option
# Basic format: internal_name:VARIABLE_NAME:Description
"age:AGE:Person's age" # Creates $AGE and --age option
# Extended format: internal_name:VARIABLE_NAME:option_name:Description
"location:LOCATION:place:Person's location" # Creates $LOCATION and --place option
)
# Process all parameters in one step
if ! param_handler::simple_handle PARAMS "$@"; then
exit 0 # Help was shown, exit successfully
fi
# Use the parameters
echo "Hello, $NAME! You are $AGE years old and from $LOCATION."
The PARAMS
array uses a specific format to define parameters:
declare -a PARAMS=(
"internal_name:VARIABLE_NAME:Description"
)
declare -a PARAMS=(
"internal_name:VARIABLE_NAME:option_name:Description[:REQUIRE][:getter_func]"
)
-
Core Components (required):
internal_name
: Used internally by the library (e.g., "user", "server")VARIABLE_NAME
: The actual variable name in your script (e.g., "USERNAME", "SERVER_ADDRESS")
-
Optional Components:
option_name
: Custom name for the command-line option (default: internal_name)REQUIRE
: Mark the parameter as requiredgetter_func
: Function name to validate or prompt for the parameter
-
Description: Help text displayed in the help message
declare -a PARAMS=(
"user:USERNAME:Username for login"
"server:SERVER_ADDRESS:Server address"
)
- Creates variables:
$USERNAME
,$SERVER_ADDRESS
- Command-line options:
--user
,--server
declare -a PARAMS=(
"user:USERNAME:username:Username for login"
"server:SERVER_ADDRESS:server-address:Server address"
)
- Creates variables:
$USERNAME
,$SERVER_ADDRESS
- Command-line options:
--username
,--server-address
declare -a PARAMS=(
"user:USERNAME:username:Username for login:REQUIRE"
"pass:PASSWORD:password:Password for authentication:REQUIRE"
"server:SERVER_ADDRESS:server-address:Server address"
)
- Creates variables:
$USERNAME
,$PASSWORD
,$SERVER_ADDRESS
- Command-line options:
--username
,--password
,--server-address
- Required parameters:
--username
,--password
declare -a PARAMS=(
"name:NAME:Person's name"
"age:AGE:Person's age"
)
Usage:
./script.sh --name "John" --age "30"
# or
./script.sh "John" "30"
declare -a PARAMS=(
"user:USERNAME:username:Login username"
"pass:PASSWORD:password:Login password"
)
Usage:
./script.sh --username "john" --password "secret"
# or
./script.sh "john" "secret"
declare -a PARAMS=(
"db:DB_NAME:database:Database name"
"host:DB_HOST:Database host"
"port:DB_PORT:db-port:Database port"
)
Usage:
./script.sh --database "mydb" --host "localhost" --db-port "5432"
# or
./script.sh "mydb" "localhost" "5432"
# or mixed
./script.sh --database "mydb" "localhost" --db-port "5432"
To use parameter validation:
- Define validator functions that return 0 for valid input and non-zero for invalid input
- Use these functions in the parameter definition
- When validation fails, the user will be prompted to enter a valid value
Example validator functions:
# Validate age (must be a number between 1-120)
validate_age() {
local value="$1"
# Check if it's a number
if ! [[ "$value" =~ ^[0-9]+$ ]]; then
echo "Age must be a number" >&2
return 1
fi
# Check range
if (( value < 1 || value > 120 )); then
echo "Age must be between 1 and 120" >&2
return 1
fi
return 0
}
# Validate email format
validate_email() {
local value="$1"
# Simple email validation
if ! [[ "$value" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Invalid email format" >&2
return 1
fi
return 0
}
Usage with validation:
declare -a PARAMS=(
"name:NAME:Person's name"
"age:AGE:age:Person's age (required, 1-120):REQUIRE:validate_age"
"email:EMAIL:email-address:Email address (required):REQUIRE:validate_email"
)
if ! param_handler::simple_handle PARAMS "$@"; then
exit 1 # Help was shown or required parameter validation failed
fi
After using param_handler::simple_handle
, you can access your parameters in several ways:
# Access variables directly
if [[ -n "$USERNAME" ]]; then
echo "Username is set to: $USERNAME"
else
echo "Username is not set"
fi
# Check if server was set by name (--server-address)
if param_handler::was_set_by_name "server"; then
echo "Server was set via --server-address option"
fi
# Check if server was set by position
if param_handler::was_set_by_position "server"; then
echo "Server was set as a positional parameter"
fi
# Get parameter value
server_address=$(param_handler::get_param "server")
echo "Server address: $server_address"
# Print all parameters with their values and sources
param_handler::print_params_extended
Function | Description | Sample |
---|---|---|
param_handler::simple_handle [params_array] [args...] |
Process parameters in one step | param_handler::simple_handle PARAMS "$@" |
param_handler::get_param [param_name] |
Get parameter value | value=$(param_handler::get_param "name") |
param_handler::was_set_by_name [param_name] |
Check if set by name | if param_handler::was_set_by_name "server"; then echo "Set via --server-address option"; fi |
param_handler::was_set_by_position [param_name] |
Check if set by position | if param_handler::was_set_by_position "user"; then echo "Set positionally"; fi |
param_handler::print_params |
Display parameter values | param_handler::print_params # Show all param values |
param_handler::print_help |
Display help message | param_handler::print_help # Show help message |
param_handler::export_params [--format type] [--prefix prefix] |
Export parameters | param_handler::export_params --format json |
Function | Description | Sample |
---|---|---|
param_handler::print_params |
Basic parameter values display | param_handler::print_params |
param_handler::print_params_extended |
Display with source information | param_handler::print_params_extended |
param_handler::print_summary |
Summary of parameter counts | param_handler::print_summary |
param_handler::print_help |
Help message | param_handler::print_help |
Function | Description | Sample |
---|---|---|
param_handler::export_params --prefix [prefix] |
Export to environment variables | param_handler::export_params --prefix "APP_" |
param_handler::export_params --format json |
Export as JSON | param_handler::export_params --format json |
The library uses colored output to indicate parameter sources:
- Green: Parameters set via named options (--option value)
- Yellow: Parameters set via positional arguments
- Red: Unset parameters
# Run with parameters by name
./script.sh --name "John" --age "30"
# Output
NAME: John (named)
AGE: 30 (named)
# Run with positional parameters
./script.sh "John" "30"
# Output
NAME: John (positional)
AGE: 30 (positional)
#!/usr/bin/bash
source "$(dirname "$0")/sh-globals.sh"
source "$(dirname "$0")/param_handler.sh"
# Initialize sh-globals
sh-globals_init "$@"
# Define validator functions
validate_age() {
local value="$1"
# Check if it's a number
if ! [[ "$value" =~ ^[0-9]+$ ]]; then
echo "Age must be a number" >&2
return 1
fi
# Check range
if (( value < 1 || value > 120 )); then
echo "Age must be between 1 and 120" >&2
return 1
fi
return 0
}
validate_email() {
local value="$1"
# Simple email validation
if ! [[ "$value" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Invalid email format" >&2
return 1
fi
return 0
}
# Define parameters
declare -a PARAMS=(
# Optional parameter (standard)
"name:NAME:Person's name"
# Required parameter with validator
"age:AGE:age:Person's age (required, 1-120):REQUIRE:validate_age"
# Required parameter with custom option name and validator
"email:EMAIL:email-address:Email address (required):REQUIRE:validate_email"
# Optional parameter with custom option name
"location:LOCATION:place:Person's location"
)
# Process all parameters
# If validation fails for required parameters, the user will be prompted
if ! param_handler::simple_handle PARAMS "$@"; then
exit 1 # Help was shown or required parameter validation failed
fi
# Display information
msg_header "Required Parameters Example"
msg_info "Parameter Values:"
echo "Name: ${NAME:-not set}"
echo "Age: ${AGE} (required)"
echo "Email: ${EMAIL} (required)"
echo "Location: ${LOCATION:-not set}"
msg_info "Parameter Sources:"
if param_handler::was_set_by_name "age"; then
msg_success "Age was provided via --age option"
elif param_handler::was_set_by_position "age"; then
msg_highlight "Age was provided as a positional parameter"
else
msg_warning "Age was provided via prompt (required parameter)"
fi
# Display parameter details
param_handler::print_params_extended
- Organized Definitions: Keep your parameter definitions organized with clear descriptions
- Use Validation: Add validation functions for critical parameters to ensure data integrity
- Use Required Flag: Mark essential parameters as required using the
REQUIRE
keyword - Descriptive Help: Write clear descriptions that will be shown in the help message
- Check Parameter Sources: Use the source checking functions when the source matters
- Export When Needed: Use export capabilities when passing parameters to other scripts
- User-Friendly Names: Use the custom option name feature to create user-friendly parameter names
tmux_utils1.sh
is a utility library for managing tmux sessions from shell scripts, providing multiple approaches for executing scripts in tmux panes with variable sharing between the host script and tmux sessions.
- Create and manage tmux sessions programmatically
- Execute scripts in tmux panes using multiple methods
- Share variables between parent script and tmux sessions
- Auto-cleanup of temporary resources
- Modular architecture with specialized utility files:
tmux_base_utils.sh
: Core low-level tmux functionstmux_script_generator.sh
: Script generation and boilerplatetmux_utils1.sh
: Main high-level functionality
The tmux utilities have been reorganized into a modular architecture:
-
tmux_base_utils.sh: Contains fundamental tmux helper functions like:
- Environment variable management (
tmx_var_set
,tmx_var_get
) - Pane ID/index management (
tmx_get_pane_id
,tmx_kill_pane_by_id
) - Self-destruct capabilities for sessions
- Environment variable management (
-
tmux_script_generator.sh: Provides script generation functionality:
- Handles script boilerplate generation
- Sets up proper environment for pane scripts
- Ensures proper utility sourcing in generated scripts
-
tmux_utils1.sh: Main library that brings it all together:
- High-level session management
- Script execution methods
- Pane creation and control
- Session monitoring and display
There are three main ways to run scripts in tmux panes:
Inline scripts with heredoc syntax - simple and direct.
# Using heredoc for inline scripts
tmx_execute_script "${SESSION_NAME}" 0 "VARS_TO_EXPORT" <<'EOF'
msg_bg_blue "This is an inline script"
echo "Current directory: $(pwd)"
# Access shared variables
echo "Variable from parent: ${SHARED_VAR}"
EOF
Benefits:
- Simple for quick one-off scripts
- No need to define separate functions
- Great for short, self-contained tasks
Loading scripts from files or functions that generate script content.
# Function that generates script content
welcome_script() {
cat <<EOF
msg_header "Welcome to \${SESSION_NAME}!"
echo "This script was generated by a function"
# Access shared variables
echo "Data file: \${DATA_FILE}"
EOF
}
# Execute the generated script
tmx_execute_function "${SESSION_NAME}" 0 welcome_script "SESSION_NAME DATA_FILE"
# Or from a file
tmx_execute_file "${SESSION_NAME}" 0 "/path/to/script.sh" "VARS_TO_EXPORT"
Benefits:
- Good for reusable script templates
- Can organize scripts in separate files
For complex cases, execute real shell functions directly:
# Define a normal shell function
monitor_files() {
local watch_dir="${WATCH_DIR:-$(pwd)}"
msg_bg_cyan "Monitoring files in: $watch_dir"
while true; do
find "$watch_dir" -type f -mtime -1 | sort
sleep 5
done
}
# Execute it in a tmux pane
tmx_execute_shell_function "${SESSION_NAME}" 0 monitor_files "WATCH_DIR"
Benefits:
- Full IDE/syntax support for function development
- Easier debugging outside of tmux
- Better integration with modern development workflows
A key feature is sharing variables between the host script and tmux sessions. The simplest approach uses files as demonstrated in the tmux_micro_counter.sh
template:
# Create files to hold shared values
COUNT_FILE="/tmp/counter_$$.txt"
echo "0" > "${COUNT_FILE}" # Initialize
# Monitor function in one pane
monitor() {
while true; do
echo "Current count: $(cat ${COUNT_FILE})"
sleep 1
done
}
# Counter function in another pane
counter() {
while true; do
v=$(($(cat ${COUNT_FILE}) + 1))
echo ${v} > ${COUNT_FILE} # Write for other panes to see
sleep 2
done
}
# Execute in different panes
tmx_execute_shell_function "${SESSION_NAME}" 0 monitor "COUNT_FILE"
tmx_execute_shell_function "${SESSION_NAME}" 1 counter "COUNT_FILE"
Function | Description |
---|---|
tmx_create_session [session_name] |
Create a new tmux session |
tmx_execute_script [session] [pane] [vars] <<EOF ... |
Execute script using heredoc |
tmx_execute_function [session] [pane] [func_name] [vars] |
Execute script from generator function |
tmx_execute_file [session] [pane] [file_path] [vars] |
Execute script from file |
tmx_execute_shell_function [session] [pane] [func_name] [vars] |
Execute shell function directly |
tmx_create_pane [session] [split_type="h"] |
Create a new pane (h=horizontal, v=vertical) |
tmx_kill_session [session] |
Kill a tmux session |
tmx_display_info [session] |
Display comprehensive session information |
tmx_create_pane_func [func_name] [session] [label] |
Create pane with smart layout and execute function |
tmx_var_set [var_name] [value] [session] |
Set a tmux environment variable |
tmx_var_get [var_name] [session] |
Get a tmux environment variable |
The Util-Sh repository contains examples demonstrating the usage of various utilities:
These examples demonstrate different aspects of tmux session and pane management:
-
tmux_micro_counter.sh
: Minimal example showing variable sharing between panes- Creates a session with three panes (monitor, green and blue counters)
- Demonstrates simple inter-pane communication using tmux environment variables
- Ideal starting point for understanding the basics
-
tmux_control_demo.sh
: Comprehensive control pane demonstration- Creates a control pane that monitors variables and manages other panes
- Implements three color-coded counter panes (green, blue, yellow)
- Shows interactive control capabilities (closing panes, quitting session)
- Uses stable pane IDs rather than indices for reliability
- Demonstrates automatic layout management
- Features comprehensive session display and monitoring
- Key Features: Auto-registration of panes, control interface, monitoring
-
tmux_simple_manage.sh
: Shows simplified management approach- Creates a basic monitoring interface
- Focuses on clean organization and minimal code
- Good for learning the core management concepts
-
tmux_status_example.sh
: Demonstrates status display capabilities- Shows how to create informative status displays
- Implements proper title management
- Provides visual session feedback
These examples demonstrate usage of the sh-globals.sh
utility:
-
sh-globals_test_colors.sh
: Demonstrates all color and formatting options- Shows all available message formatting functions
- Visual demonstration of colors and styles
- Useful reference for UI design
-
sh-globals_template.sh
: Bare-bones template for new scripts- Minimal working example with proper initialization
- Ready-to-use structure for new scripts
- Includes standard error handling
These examples demonstrate the parameter handling capabilities:
-
params_example.sh
: Basic parameter handling demonstration- Shows simple named and positional parameters
- Demonstrates automatic help generation
- Includes parameter display functions
-
params_required_example.sh
: Required parameter validation- Demonstrates parameter validation with custom validators
- Shows required parameter enforcement
- Implements interactive prompting for missing parameters
-
param_handler_formats.sh
: Shows different output formats- Demonstrates exporting parameters in various formats
- Shows JSON export capabilities
- Illustrates environment variable exports
-
param_handler_usage.sh
: Comprehensive usage examples- Complete reference for parameter handling features
- Includes advanced usage patterns
- Shows parameter state checking
-
param_handler_ordered_usage.sh
: Ordered parameter handling- Demonstrates maintaining parameter order
- Shows advanced parameter tracking
- Implements comprehensive parameter testing
Here's a minimal working example based on the tmux_micro_counter.sh
template:
#!/usr/bin/env bash
# Source required utilities
source "$(dirname "$0")/sh-globals.sh"
source "$(dirname "$0")/tmux_base_utils.sh" # New dependency
source "$(dirname "$0")/tmux_script_generator.sh" # New dependency
source "$(dirname "$0")/tmux_utils1.sh"
sh-globals_init "$@"
# Create shared files for inter-pane communication
COUNT_GREEN="/tmp/counter_green_$$.txt"
COUNT_BLUE="/tmp/counter_blue_$$.txt"
echo "0" > "${COUNT_GREEN}"
echo "0" > "${COUNT_BLUE}"
# Monitor function to display both counters
monitor() {
while true; do
clear
echo "=== MONITOR ==="
echo "GREEN: $(cat ${COUNT_GREEN})"
echo "BLUE: $(cat ${COUNT_BLUE})"
sleep 1
done
}
# Green counter function - increments by 2
green() {
while true; do
v=$(($(cat ${COUNT_GREEN}) + 2))
echo ${v} > ${COUNT_GREEN}
clear
msg_bg_green "GREEN COUNTER (PANE 1)"
msg_green "Value: ${v}"
msg_green "Press '1' in control pane to close"
sleep 1
done
}
# Blue counter function - increments by 3 every 2 seconds
blue() {
local session="$1"
while true; do
local current_blue=$(tmx_var_get "counter_blue" "$session")
local v=$((current_blue + 3))
tmx_var_set "counter_blue" "$v" "$session"
clear
msg_bg_blue "BLUE COUNTER (PANE 2)"
msg_blue "Value: ${v}"
msg_blue "Press '2' in control pane to close"
sleep 2
done
}
# Create tmux session and run functions in panes
main() {
s=$(tmx_create_session "counter_$(date +%s)")
# Start monitor in first pane
tmx_execute_shell_function "${s}" 0 monitor "COUNT_GREEN COUNT_BLUE"
# Create and populate additional panes
p1=$(tmx_create_pane "${s}" "v")
tmx_execute_shell_function "${s}" "${p1}" green "COUNT_GREEN"
p2=$(tmx_create_pane "${s}")
tmx_execute_shell_function "${s}" "${p2}" blue "COUNT_BLUE"
# Set up cleanup on exit
trap 'rm -f "${COUNT_GREEN}" "${COUNT_BLUE}"; exit 0' INT
# Keep parent script running
echo "Running in: ${s} - Press Ctrl+C to exit"
while true; do sleep 1; done
}
main
This example demonstrates how to use sh-globals.sh
, param_handler.sh
, and the tmux_utils1.sh
suite together, based on the util-sh_combine_sample.sh
sample.
#!/usr/bin/env bash
# util-sh_combine_sample.sh - Combined example of utilities
# Demonstrates param handling and tmux session control
# shellcheck disable=SC1091,SC2317,SC2155,SC2034,SC2250,SC2162,SC2312
# Get the directory where this script is located
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# Source the libraries (in the correct order)
source "${SCRIPT_DIR}/sh-globals.sh"
source "${SCRIPT_DIR}/param_handler.sh"
source "${SCRIPT_DIR}/tmux_base_utils.sh"
source "${SCRIPT_DIR}/tmux_script_generator.sh"
source "${SCRIPT_DIR}/tmux_utils1.sh"
# Initialize sh-globals with script arguments - this sets _MAIN_SCRIPT_NAME
sh-globals_init "$@"
# Initialize logging if not already initialized
[[ $_LOG_INITIALIZED -eq 0 ]] && log_init "" 0
# Set up logging - now get_script_name will return the correct script name
log_info "Starting script: $(get_script_name)"
# Print a header for the script
msg_header "TMUX CONTROL DEMO (Combined Example)"
msg_section "Environment Setup" 60 "-"
# Check dependencies
msg_info "Checking dependencies..."
if ! check_dependencies tmux; then
msg_error "Missing required dependency: tmux"
exit 1
fi
# Define parameters with param_handler
declare -a PARAMS=(
"name:SESSION_NAME:session:Tmux session name (default: control_demo_TIMESTAMP)"
"headless:HEADLESS:Run in headless mode (no terminal launch)"
)
# Process parameters
if ! param_handler::simple_handle PARAMS "$@"; then
exit 1 # Help was shown or parameter validation failed
fi
# Set defaults for optional parameters
SESSION_NAME="${SESSION_NAME:-control_demo_$(date +%s)}"
LAUNCH_TERMINAL="true"
[[ -n "$HEADLESS" ]] && LAUNCH_TERMINAL="false"
# === Counter pane functions ===
# Green counter: Increments by 2 every second
Green() {
local session="$1"
while true; do
local current_green=$(tmx_var_get "counter_green" "$session" 2>/dev/null || echo 0)
local v=$((current_green + 2))
tmx_var_set "counter_green" "$v" "$session"
clear
msg_bg_green "GREEN COUNTER (PANE 1)"
msg_green "Value: ${v}"
msg_green "Press '1' in control pane to close"
sleep 1
done
}
# Blue counter: Increments by 3 every 2 seconds
Blue() {
local session="$1"
while true; do
local current_blue=$(tmx_var_get "counter_blue" "$session" 2>/dev/null || echo 0)
local v=$((current_blue + 3))
tmx_var_set "counter_blue" "$v" "$session"
clear
msg_bg_blue "BLUE COUNTER (PANE 2)"
msg_blue "Value: ${v}"
msg_blue "Press '2' in control pane to close"
sleep 2
done
}
# Yellow counter: Increments by 5 every 3 seconds
Yellow() {
local session="$1"
while true; do
local current_yellow=$(tmx_var_get "counter_yellow" "$session" 2>/dev/null || echo 0)
local v=$((current_yellow + 5))
tmx_var_set "counter_yellow" "$v" "$session"
clear
msg_bg_yellow "YELLOW COUNTER (PANE 3)"
msg_yellow "Value: ${v}"
msg_yellow "Press '3' in control pane to close"
sleep 3
done
}
# === Shared variables ===
# Define which variables to initialize and track
COUNTER_VARS=("counter_green" "counter_blue" "counter_yellow")
# === Main function ===
main() {
msg_section "Creating Tmux Session" 60 "-"
# Create the session and initialize counter variables to 0
msg_info "Creating tmux session: $SESSION_NAME"
if ! tmx_create_session_with_vars "$SESSION_NAME" COUNTER_VARS 0 "$LAUNCH_TERMINAL"; then
msg_error "Failed to create tmux session '$SESSION_NAME'"
exit 1
fi
# Get the actual session name used (might be different if handled duplicates)
local actual_session_name="${TMX_SESSION_NAME}"
msg_success "Tmux session '$actual_session_name' created"
# Create panes and run counter functions in them with auto-registration
msg_info "Creating counter panes..."
local p1_id=$(tmx_new_pane_func Green "$actual_session_name" "Green Counter")
local p2_id=$(tmx_new_pane_func Blue "$actual_session_name" "Blue Counter")
local p3_id=$(tmx_new_pane_func Yellow "$actual_session_name" "Yellow Counter")
# Use pane 0 (the first pane) as the control pane
msg_info "Creating monitoring control pane..."
local p0_id=$(tmx_create_monitoring_control "$actual_session_name" COUNTER_VARS "PANE" "1" "0")
# Make sure titles are enabled
tmx_enable_pane_titles "$actual_session_name"
# Display session information
tmx_display_info "$actual_session_name"
# Monitor the session until it terminates
tmx_monitor_session "$actual_session_name" 0.5 "Monitoring session '$actual_session_name'... Press Ctrl+C to exit."
msg_success "Session closed. Goodbye!"
}
# Run the main function
main
exit $?
This example demonstrates:
- Initialization: Setting up all libraries (
sh-globals
,param_handler
,tmux_base_utils
,tmux_script_generator
,tmux_utils1
) and initializing with script arguments. - Logging: Using both log functions and colorized message display from
sh-globals.sh
. - Parameter Handling: Using
param_handler.sh
to process command-line arguments like--session
and--headless
. - Tmux Session Management: Creating and managing a tmux session with multiple panes running counter functions.
- Tmux Function Usage: Utilizing functions like
tmx_create_session_with_vars
,tmx_new_pane_func
,tmx_create_monitoring_control
,tmx_enable_pane_titles
,tmx_display_info
, andtmx_monitor_session
. - Variable Sharing: Demonstrates variable sharing between panes using
tmx_var_set
/tmx_var_get
within the counter functions.
These utilities are provided as open source under the MIT License. Feel free to use and modify as needed.