Shell Scripting
Generate POSIX-compliant shell scripts that follow UNIX philosophy and rigorous engineering practices.
Core Principles
Apply these principles to all shell scripts:
- •UNIX Philosophy: Silent success, errors to stderr, consistent exit codes
- •Rigorous Quoting: Always quote variables (
"${var}","$@") - •Standard Structure: Template functions → Program functions → Parameters → Main
- •Modular Design: Use
#includedirectives for reusable components - •Self-Documenting: Use
#_#prefix for help text - •Atomic Operations: Safe file writes using temp files + mv
Quick Start
Basic Script Structure
Every script follows this template:
#!/bin/sh
#### template functions
#include "shout.sh"
#include "barf.sh"
#include "usage.sh"
#include "do_help.sh"
#### program functions
#_# command args...
#_# Description of command
#_#
do_command() {
# implementation
}
#### parameters
# Configuration variables here
#### main
test $# -gt 0 || usage "$0 command [args]"
"do_$@"
Standard Error Functions
shout() { printf '%s\n' "$0: $*" >&2; } # Print to stderr
barf() { shout "fatal: $*"; exit 111; } # Fatal error, exit 111
usage() { shout "usage: $*"; exit 100; } # Usage error, exit 100
Variable Quoting Rules
# Correct - always quote, use braces for multi-character names
local filename="$1"
test -f "${filename}"
"${command}" "${arg1}" "${arg2}"
# Single-digit positional parameters don't need braces
shift_count="$1"
process "$2" "$3"
# Special cases
"$@" # All args as separate quoted words
"$*" # All args as single word
$# # Number of args (safe unquoted)
$? # Exit code (safe unquoted)
$$ # Process ID (safe unquoted)
# Exception: Intentional unquoted usage must be commented
for file in ${pattern} # intentional: word splitting needed
do
process "${file}"
done
Essential Patterns
Subcommand Dispatch
#_# build
#_# Build the project
#_#
do_build() {
make
}
#_# test
#_# Run tests
#_#
do_test() {
./run-tests
}
#### main
test $# -gt 0 || usage "$0 build|test|help"
"do_$@"
Atomic File Operations
#include "atomic_to.sh" # Write atomically: creates temp → writes → moves atomic_to "output.txt" sed 's/foo/bar/g' input.txt atomic_to "config.json" jq '.setting = "value"' raw.json
Error Detection
# Fail on error command || barf "command failed" # Check file exists test -f "$file" || barf "file not found: $file" # Validate arguments test $# -eq 2 || usage "$0 source dest"
Pipeline Construction
#include "pipeline.sh" # Build pipelines with custom separator pipeline '::' cat file.txt '::' grep pattern '::' sort
Standard Library
The assets/stdlib/ directory contains reusable shell functions:
Core Functions:
- •
shout.sh- Print messages to stderr - •
barf.sh- Fatal error handling - •
usage.sh- Usage error handling - •
do_help.sh- Self-documenting help extraction
File Operations:
- •
atomic_to.sh- Atomic file writes - •
atomic_to_mode.sh- Atomic writes with permissions
Utilities:
- •
pipeline.sh- Pipeline construction - •
pipewith.sh- Flexible pipeline builder - •
catch.sh- Error pattern detection - •
safe.sh- Safe command execution - •
do_.sh- Subcommand dispatcher - •
do_run.sh,do_xrun.sh- Command runners - •
have_args.sh- Argument validation
Include these in scripts using #include directives:
#include "shout.sh" #include "barf.sh" #include "atomic_to.sh"
Detailed Documentation
For comprehensive guidelines and patterns:
- •references/style-guide.md - Complete style conventions, quoting rules, standard functions, and UNIX philosophy application
- •references/patterns.md - Common patterns, complete examples, error handling, file operations, and text processing
Read these references when:
- •Starting a complex script
- •Unsure about a pattern
- •Need examples of specific functionality
- •Want to understand the rationale behind conventions
Templates and Tools
Script Template
Use assets/template.sh as a starting point for new scripts. It includes:
- •Standard structure
- •Common includes
- •Placeholder functions
- •Main dispatcher
Initialization Script
Run scripts/init-script.sh to create new scripts:
scripts/init-script.sh my-script output-dir/
Creates a properly structured script ready for implementation.
Exit Codes
Use consistent exit codes:
- •0 - Success (silent)
- •100 - Usage error (wrong arguments)
- •111 - Fatal error (runtime failure)
Workflow
- •Start with template: Use
assets/template.shor runscripts/init-script.sh - •Include standard functions: Add
#includedirectives for needed utilities - •Define program functions: Implement
do_*functions with#_#help text - •Add parameters: Define configuration variables in parameters section
- •Implement main: Add argument validation and dispatch logic
- •Test error paths: Verify
barf()andusage()work correctly - •Verify quoting: Ensure all variables are quoted properly
Common Scenarios
Simple utility script
Use template with basic includes (shout, barf, usage, do_help)
File processing script
Include atomic_to.sh for safe file operations
Pipeline builder
Include pipeline.sh and pipewith.sh for composable commands
Multi-command tool
Use subcommand pattern with do_* functions and main dispatcher
Build/deployment automation
Combine atomic operations, error checking, and subcommand dispatch