shell-guide

Applies to: Bash 4+, POSIX sh, Automation Scripts, CI/CD Pipelines, Makefiles

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "shell-guide" with this command: npx skills add ar4mirez/samuel/ar4mirez-samuel-shell-guide

Shell/Bash Guide

Applies to: Bash 4+, POSIX sh, Automation Scripts, CI/CD Pipelines, Makefiles

Core Principles

  • Strict Mode Always: Every script starts with set -euo pipefail to fail fast on errors

  • Quote Everything: All variable expansions must be double-quoted to prevent word splitting and globbing

  • Explicit Over Implicit: Use [[ ]] for conditionals, local for function variables, named constants for magic values

  • Fail Loudly: Never swallow errors silently; use trap for cleanup and meaningful exit codes

  • ShellCheck Clean: All scripts pass shellcheck with zero warnings before commit

Guardrails

Shebang and Strict Mode

  • Every script: #!/usr/bin/env bash (or #!/bin/sh for POSIX)

  • Immediately follow with set -euo pipefail

  • Use set -x only for debugging, never in production scripts

  • POSIX scripts must not use bash-specific features ([[ ]] , arrays, local )

#!/usr/bin/env bash set -euo pipefail [[ "${TRACE:-}" == "1" ]] && set -x

Quoting

  • Always double-quote: "$var" , "$@" , "${arr[@]}" , "$(command)"

  • Single quotes for literals that must not be interpolated

  • Only omit quotes in arithmetic: $(( count + 1 ))

Correct

grep -r "$pattern" "$directory" for arg in "$@"; do process "$arg"; done

Wrong - word splitting and globbing bugs

grep -r $pattern $directory for arg in $@; do process $arg; done

Error Handling

  • Check return codes: if ! command; then handle_error; fi

  • Inline: critical_cmd || { echo "Failed" >&2; exit 1; }

  • Never use set +e (restructure logic instead)

  • Exit codes: 0 = success, 1 = general error, 2 = usage error

  • Errors to stderr: echo "Error: message" >&2

Portability

  • #!/usr/bin/env bash over #!/bin/bash (varies across systems)

  • command -v instead of which for executable checks

  • $(command) instead of backticks

  • printf over echo for portable output (flags/escapes differ)

Security

  • Never use eval (use arrays for dynamic command building)

  • Validate all external input (arguments, env vars, file contents)

  • mktemp for temp files, never hardcoded /tmp/myapp.tmp

  • No secrets in script files; read from environment or secret managers

  • umask 077 before creating sensitive files

Safe temp file

tmpfile="$(mktemp)" || exit 1 trap 'rm -f "$tmpfile"' EXIT

Never do this

eval "$user_input" # Command injection password="hunter2" # Hardcoded secret

Script Structure

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

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

── Configuration (with defaults) ─────────────────────

LOG_LEVEL="${LOG_LEVEL:-info}" OUTPUT_DIR="${OUTPUT_DIR:-./output}"

── Functions ──────────────────────────────────────────

usage() { ... } cleanup() { ... } main() { ... }

── Traps & Entry ─────────────────────────────────────

trap cleanup EXIT main "$@"

Key Patterns

Parameter Expansion

db_host="${DB_HOST:-localhost}" # Default value api_key="${API_KEY:?Error: API_KEY required}" # Required (fail if unset)

filename="archive.tar.gz" name="${filename%%.}" # "archive" (longest suffix removal) ext="${filename#.}" # "tar.gz" (shortest prefix removal) path="/usr/local/bin/tool" dir="${path%/}" # "/usr/local/bin" base="${path##/}" # "tool" upper="${var^^}" # UPPERCASE (Bash 4+) lower="${var,,}" # lowercase (Bash 4+)

Trap for Cleanup

cleanup() { local exit_code=$? rm -f "$tmpfile" exit "$exit_code" # Preserve original exit code } trap cleanup EXIT trap 'echo "Interrupted" >&2; exit 130' INT TERM

Arrays (Avoid eval)

declare -a files=() files+=("first.txt" "second.txt") for file in "${files[@]}"; do echo "$file"; done

Build commands safely with arrays

cmd=(curl --silent --fail) [[ -n "${TOKEN:-}" ]] && cmd+=(--header "Authorization: Bearer $TOKEN") "${cmd[@]}" "$url"

Functions

process_file() { local file="$1" local -r max_lines=1000 local line_count line_count="$(wc -l < "$file")" if (( line_count > max_lines )); then echo "Warning: $file exceeds $max_lines lines" >&2 fi }

All variables inside functions must be declared local .

Here Documents

cat <<EOF # Interpolated Hello, $USER at $(hostname) EOF

cat <<'EOF' # Literal (no expansion) This $variable stays literal. EOF

Safe File Iteration

Handles spaces, newlines, special characters

while IFS= read -r -d '' file; do process "$file" done < <(find "$dir" -type f -name "*.log" -print0)

Simple globs (Bash 4+)

shopt -s nullglob globstar for file in "$dir"/**/*.sh; do process "$file"; done

Never use for file in $(find ...) -- it breaks on spaces.

Process Substitution

diff <(sort file1.txt) <(sort file2.txt)

Testing

bats-core

test/deploy.bats

setup() { export TMPDIR="$(mktemp -d)"; } teardown() { rm -rf "$TMPDIR"; }

@test "deploy requires environment argument" { run ./deploy.sh [ "$status" -ne 0 ] [[ "$output" == "Usage:" ]] }

Testing Standards

  • Test with bats-core (preferred) or shellspec

  • Test files in test/ or spec/ directory

  • Test names describe behavior: "deploy requires environment argument"

  • Use setup /teardown for temp dirs and fixtures

  • Coverage: >80% library functions, >60% scripts

  • Each test must be independent

Tooling

ShellCheck

shellcheck script.sh # Single file find . -name "*.sh" -exec shellcheck {} + # All scripts

Suppress with justification

shellcheck disable=SC2034 # Variable used by sourced script

unused_looking_var="value"

shfmt

shfmt -w -i 4 -bn script.sh # Format in place (4-space indent) shfmt -d -i 4 script.sh # Check only (diff output)

Essential Commands

shellcheck *.sh # Lint shfmt -d -i 4 *.sh # Check formatting bats test/ # Run tests bash -n script.sh # Syntax check (no execution)

References

For detailed patterns and examples, see:

  • references/patterns.md -- Script templates, trap patterns, portable scripting examples

External References

  • Bash Reference Manual

  • POSIX Shell Specification

  • ShellCheck Wiki

  • Google Shell Style Guide

  • bats-core

  • shellspec

  • shfmt

  • Pure Bash Bible

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

generate-agents-md

No summary provided by upstream source.

Repository SourceNeeds Review
General

actix-web

No summary provided by upstream source.

Repository SourceNeeds Review
General

frontend-design

No summary provided by upstream source.

Repository SourceNeeds Review
Security

security-audit

No summary provided by upstream source.

Repository SourceNeeds Review