Install
$ agentstack add skill-geniushtx-swe-skills-bench-bash-defensive-patterns ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Bash Defensive Patterns
Comprehensive guidance for writing production-ready Bash scripts using defensive programming techniques, error handling, and safety best practices to prevent common pitfalls and ensure reliability.
When to Use This Skill
- Writing production automation scripts
- Building CI/CD pipeline scripts
- Creating system administration utilities
- Developing error-resilient deployment automation
- Writing scripts that must handle edge cases safely
- Building maintainable shell script libraries
- Implementing comprehensive logging and monitoring
- Creating scripts that must work across different platforms
Core Defensive Principles
1. Strict Mode
Enable bash strict mode at the start of every script to catch errors early.
#!/bin/bash
set -Eeuo pipefail # Exit on error, unset variables, pipe failures
Key flags:
set -E: Inherit ERR trap in functionsset -e: Exit on any error (command returns non-zero)set -u: Exit on undefined variable referenceset -o pipefail: Pipe fails if any command fails (not just last)
2. Error Trapping and Cleanup
Implement proper cleanup on script exit or error.
#!/bin/bash
set -Eeuo pipefail
trap 'echo "Error on line $LINENO"' ERR
trap 'echo "Cleaning up..."; rm -rf "$TMPDIR"' EXIT
TMPDIR=$(mktemp -d)
# Script code here
3. Variable Safety
Always quote variables to prevent word splitting and globbing issues.
# Wrong - unsafe
cp $source $dest
# Correct - safe
cp "$source" "$dest"
# Required variables - fail with message if unset
: "${REQUIRED_VAR:?REQUIRED_VAR is not set}"
4. Array Handling
Use arrays safely for complex data handling.
# Safe array iteration
declare -a items=("item 1" "item 2" "item 3")
for item in "${items[@]}"; do
echo "Processing: $item"
done
# Reading output into array safely
mapfile -t lines &2
return 1
fi
return 0
}
process_files() {
local -r input_dir="$1"
local -r output_dir="$2"
# Validate inputs
[[ -d "$input_dir" ]] || { echo "ERROR: input_dir not a directory" >&2; return 1; }
# Create output directory if needed
mkdir -p "$output_dir" || { echo "ERROR: Cannot create output_dir" >&2; return 1; }
# Process files safely
while IFS= read -r -d '' file; do
echo "Processing: $file"
# Do work
done &2; exit 1; }
# Create temporary files in directory
TMPFILE1="$TMPDIR/temp1.txt"
TMPFILE2="$TMPDIR/temp2.txt"
# Use temporary files
touch "$TMPFILE1" "$TMPFILE2"
echo "Temp files created in: $TMPDIR"
Pattern 4: Robust Argument Parsing
#!/bin/bash
set -Eeuo pipefail
# Default values
VERBOSE=false
DRY_RUN=false
OUTPUT_FILE=""
THREADS=4
usage() {
cat &2
usage 1
;;
esac
done
# Validate required arguments
[[ -n "$OUTPUT_FILE" ]] || { echo "ERROR: -o/--output is required" >&2; usage 1; }
Pattern 5: Structured Logging
#!/bin/bash
set -Eeuo pipefail
# Logging functions
log_info() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO: $*" >&2
}
log_warn() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] WARN: $*" >&2
}
log_error() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $*" >&2
}
log_debug() {
if [[ "${DEBUG:-0}" == "1" ]]; then
echo "[$(date +'%Y-%m-%d %H:%M:%S')] DEBUG: $*" >&2
fi
}
# Usage
log_info "Starting script"
log_debug "Debug information"
log_warn "Warning message"
log_error "Error occurred"
Pattern 6: Process Orchestration with Signals
#!/bin/bash
set -Eeuo pipefail
# Track background processes
PIDS=()
cleanup() {
log_info "Shutting down..."
# Terminate all background processes
for pid in "${PIDS[@]}"; do
if kill -0 "$pid" 2>/dev/null; then
kill -TERM "$pid" 2>/dev/null || true
fi
done
# Wait for graceful shutdown
for pid in "${PIDS[@]}"; do
wait "$pid" 2>/dev/null || true
done
}
trap cleanup SIGTERM SIGINT
# Start background tasks
background_task &
PIDS+=($!)
another_task &
PIDS+=($!)
# Wait for all background processes
wait
Pattern 7: Safe File Operations
#!/bin/bash
set -Eeuo pipefail
# Use -i flag to move safely without overwriting
safe_move() {
local -r source="$1"
local -r dest="$2"
if [[ ! -e "$source" ]]; then
echo "ERROR: Source does not exist: $source" >&2
return 1
fi
if [[ -e "$dest" ]]; then
echo "ERROR: Destination already exists: $dest" >&2
return 1
fi
mv "$source" "$dest"
}
# Safe directory cleanup
safe_rmdir() {
local -r dir="$1"
if [[ ! -d "$dir" ]]; then
echo "ERROR: Not a directory: $dir" >&2
return 1
fi
# Use -I flag to prompt before rm (BSD/GNU compatible)
rm -rI -- "$dir"
}
# Atomic file writes
atomic_write() {
local -r target="$1"
local -r tmpfile
tmpfile=$(mktemp) || return 1
# Write to temp file first
cat > "$tmpfile"
# Atomic rename
mv "$tmpfile" "$target"
}
Pattern 8: Idempotent Script Design
#!/bin/bash
set -Eeuo pipefail
# Check if resource already exists
ensure_directory() {
local -r dir="$1"
if [[ -d "$dir" ]]; then
log_info "Directory already exists: $dir"
return 0
fi
mkdir -p "$dir" || {
log_error "Failed to create directory: $dir"
return 1
}
log_info "Created directory: $dir"
}
# Ensure configuration state
ensure_config() {
local -r config_file="$1"
local -r default_value="$2"
if [[ ! -f "$config_file" ]]; then
echo "$default_value" > "$config_file"
log_info "Created config: $config_file"
fi
}
# Rerunning script multiple times should be safe
ensure_directory "/var/cache/myapp"
ensure_config "/etc/myapp/config" "DEBUG=false"
Pattern 9: Safe Command Substitution
#!/bin/bash
set -Eeuo pipefail
# Use $() instead of backticks
name=$(&2
return 1
;;
esac
shift
done
# Validate required parameters
[[ -n "$input_file" ]] || { echo "ERROR: --input is required" >&2; return 1; }
[[ -n "$output_dir" ]] || { echo "ERROR: --output is required" >&2; return 1; }
}
Dependency Checking
#!/bin/bash
set -Eeuo pipefail
check_dependencies() {
local -a missing_deps=()
local -a required=("jq" "curl" "git")
for cmd in "${required[@]}"; do
if ! command -v "$cmd" &>/dev/null; then
missing_deps+=("$cmd")
fi
done
if [[ ${#missing_deps[@]} -gt 0 ]]; then
echo "ERROR: Missing required commands: ${missing_deps[*]}" >&2
return 1
fi
}
check_dependencies
Best Practices Summary
- Always use strict mode -
set -Eeuo pipefail - Quote all variables -
"$variable"prevents word splitting - Use [[]] conditionals - More robust than [ ]
- Implement error trapping - Catch and handle errors gracefully
- Validate all inputs - Check file existence, permissions, formats
- Use functions for reusability - Prefix with meaningful names
- Implement structured logging - Include timestamps and levels
- Support dry-run mode - Allow users to preview changes
- Handle temporary files safely - Use mktemp, cleanup with trap
- Design for idempotency - Scripts should be safe to rerun
- Document requirements - List dependencies and minimum versions
- Test error paths - Ensure error handling works correctly
- Use
command -v- Safer thanwhichfor checking executables - Prefer printf over echo - More predictable across systems
Resources
- Bash Strict Mode: http://redsymbol.net/articles/unofficial-bash-strict-mode/
- Google Shell Style Guide: https://google.github.io/styleguide/shellguide.html
- Defensive BASH Programming: https://www.lifepipe.net/
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: GeniusHTX
- Source: GeniusHTX/SWE-Skills-Bench
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.