Agent Skill
2/7/2026

bash-development

This skill should be used when the user asks to "write a bash script", "create a shell script", "implement bash function", "parse arguments in bash", "handle errors in bash", or mentions bash development, shell scripting, script templates, or modern bash patterns.

J
jamie
16GitHub Stars
1Views
npx skills add Jamie-BitFlight/claude_skills

SKILL.md

Namebash-development
DescriptionThis skill should be used when the user asks to "write a bash script", "create a shell script", "implement bash function", "parse arguments in bash", "handle errors in bash", or mentions bash development, shell scripting, script templates, or modern bash patterns.

name: bash-development description: This skill should be used when the user asks to "write a bash script", "create a shell script", "implement bash function", "parse arguments in bash", "handle errors in bash", or mentions bash development, shell scripting, script templates, or modern bash patterns.

Bash Development

Core patterns and best practices for Bash 5.1+ script development. Provides modern bash idioms, error handling, argument parsing, and pure-bash alternatives to external commands.

Script Foundation

Every script starts with the essential header:

#!/usr/bin/env bash
set -euo pipefail

set options explained:

  • -e - Exit immediately on command failure
  • -u - Treat unset variables as errors
  • -o pipefail - Pipeline fails if any command fails

Script Metadata Pattern

SCRIPT_NAME=$(basename "${BASH_SOURCE[0]}")
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
readonly SCRIPT_VERSION="1.0.0"
readonly SCRIPT_NAME SCRIPT_DIR

Error Handling

Implement trap-based error handling for robust scripts:

handle_error() {
    local line="${1}"
    local exit_code="${2:-1}"
    printf '%s\n' "Error on line ${line}" >&2
    exit "${exit_code}"
}

trap 'handle_error ${LINENO} $?' ERR

cleanup() {
    # Cleanup logic here
    rm -f "${TEMP_FILE:-}"
}

trap cleanup EXIT

Argument Parsing

Standard argument parsing template:

usage() {
    cat <<EOF
Usage: ${SCRIPT_NAME} [OPTIONS] <argument>

Options:
    -h, --help      Show this help message
    -v, --version   Show version information
    -d, --debug     Enable debug mode
    -f, --file      Specify input file

Examples:
    ${SCRIPT_NAME} file.txt
    ${SCRIPT_NAME} --debug file.txt
EOF
}

main() {
    local debug=0
    local input_file=""

    while [[ $# -gt 0 ]]; do
        case "${1}" in
            -h|--help) usage; exit 0 ;;
            -v|--version) printf '%s version %s\n' "${SCRIPT_NAME}" "${SCRIPT_VERSION}"; exit 0 ;;
            -d|--debug) debug=1; set -x; shift ;;
            -f|--file) input_file="${2}"; shift 2 ;;
            -*) printf 'Unknown option: %s\n' "${1}" >&2; usage; exit 1 ;;
            *) break ;;
        esac
    done

    # Validate required arguments
    if [[ $# -lt 1 ]]; then
        printf 'Missing required argument\n' >&2
        usage
        exit 1
    fi

    # Main logic here
}

main "$@"

Variable Best Practices

Always use curly braces and quote variables:

# Correct
"${variable}"
"${array[@]}"

# Incorrect
$variable
${array[*]}  # Use [@] for proper iteration

Use readonly for constants:

readonly CONFIG_FILE="/etc/app/config"
readonly -a VALID_OPTIONS=("opt1" "opt2" "opt3")

Note: Never use readonly in sourced scripts - it causes errors on re-sourcing.

String Operations (Pure Bash)

Prefer native bash parameter expansion over external tools:

# Trim whitespace
trimmed="${string#"${string%%[![:space:]]*}"}"
trimmed="${trimmed%"${trimmed##*[![:space:]]}"}"

# Lowercase/Uppercase (Bash 4+)
lower="${string,,}"
upper="${string^^}"

# Substring extraction
substring="${string:0:10}"      # First 10 chars
suffix="${string: -5}"          # Last 5 chars

# Replace patterns
replaced="${string//old/new}"   # Replace all
replaced="${string/old/new}"    # Replace first

# Strip prefix/suffix
no_prefix="${string#prefix}"    # Shortest match
no_prefix="${string##*/}"       # Longest match (basename)
no_suffix="${string%suffix}"    # Shortest match
no_suffix="${string%%/*}"       # Longest match

Array Operations

# Declaration
declare -a indexed_array=()
declare -A assoc_array=()

# Safe iteration with nullglob
shopt -s nullglob
for file in *.txt; do
    process "${file}"
done
shopt -u nullglob

# Array length
length="${#array[@]}"

# Append element
array+=("new_element")

# Iterate with index
for i in "${!array[@]}"; do
    printf '%d: %s\n' "${i}" "${array[i]}"
done

File Operations

# Read file to string
content="$(<"${file}")"

# Read file to array (Bash 4+)
mapfile -t lines < "${file}"

# Check file conditions
[[ -f "${file}" ]]    # Regular file exists
[[ -d "${dir}" ]]     # Directory exists
[[ -r "${file}" ]]    # Readable
[[ -w "${file}" ]]    # Writable
[[ -x "${file}" ]]    # Executable
[[ -s "${file}" ]]    # Non-empty

# Safe temp file creation
temp_file=$(mktemp)
trap 'rm -f "${temp_file}"' EXIT

Conditional Expressions

Use [[ ]] for conditionals (bash-specific, more powerful):

# String comparisons
[[ "${var}" == "value" ]]       # Equality
[[ "${var}" == pattern* ]]     # Glob matching
[[ "${var}" =~ ^regex$ ]]      # Regex matching

# Numeric comparisons
(( num > 10 ))                  # Arithmetic comparison
[[ "${num}" -gt 10 ]]          # Traditional syntax

# Compound conditions
[[ -f "${file}" && -r "${file}" ]]
[[ "${opt}" == "a" || "${opt}" == "b" ]]

Utility Functions

# Check command existence
command_exists() {
    command -v "${1}" >/dev/null 2>&1
}

# Get script directory (resolves symlinks)
get_script_dir() {
    local source="${BASH_SOURCE[0]}"
    while [[ -L "${source}" ]]; do
        local dir=$(cd -P "$(dirname "${source}")" && pwd)
        source=$(readlink "${source}")
        [[ "${source}" != /* ]] && source="${dir}/${source}"
    done
    cd -P "$(dirname "${source}")" && pwd
}

# Conditional sudo
run_privileged() {
    if [[ "${EUID}" -eq 0 ]]; then
        "$@"
    elif command_exists sudo; then
        sudo "$@"
    else
        printf 'Error: root privileges required\n' >&2
        return 1
    fi
}

Performance Guidelines

  • Use builtins over external commands when possible
  • Batch operations instead of loops for large datasets
  • Use printf over echo for portability and control
  • Avoid unnecessary subshells in tight loops
  • Use [[ ]] over [ ] for string comparisons

Additional Resources

Reference Files

For detailed patterns and examples:

Skills Info
Original Name:bash-developmentAuthor:jamie