internal/skills/content/shell-guide/SKILL.md
Shell/Bash scripting guardrails, patterns, and best practices for AI-assisted development. Use when working with shell scripts (.sh, .bash), Makefiles, or when the user mentions Bash/Shell. Provides POSIX compliance guidelines, error handling patterns, and ShellCheck rules specific to this project's coding standards.
npx skillsauth add ar4mirez/samuel shell-guideInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Applies to: Bash 4+, POSIX sh, Automation Scripts, CI/CD Pipelines, Makefiles
set -euo pipefail to fail fast on errors[[ ]] for conditionals, local for function variables, named constants for magic valuestrap for cleanup and meaningful exit codesshellcheck with zero warnings before commit#!/usr/bin/env bash (or #!/bin/sh for POSIX)set -euo pipefailset -x only for debugging, never in production scripts[[ ]], arrays, local)#!/usr/bin/env bash
set -euo pipefail
[[ "${TRACE:-}" == "1" ]] && set -x
"$var", "$@", "${arr[@]}", "$(command)"$(( 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
if ! command; then handle_error; ficritical_cmd || { echo "Failed" >&2; exit 1; }set +e (restructure logic instead)echo "Error: message" >&2#!/usr/bin/env bash over #!/bin/bash (varies across systems)command -v instead of which for executable checks$(command) instead of backticksprintf over echo for portable output (flags/escapes differ)eval (use arrays for dynamic command building)mktemp for temp files, never hardcoded /tmp/myapp.tmpumask 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
#!/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 "$@"
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+)
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
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"
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.
cat <<EOF # Interpolated
Hello, $USER at $(hostname)
EOF
cat <<'EOF' # Literal (no expansion)
This $variable stays literal.
EOF
# 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.
diff <(sort file1.txt) <(sort file2.txt)
# 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:"* ]]
}
bats-core (preferred) or shellspectest/ or spec/ directory"deploy requires environment argument"setup/teardown for temp dirs and fixturesshellcheck 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 -w -i 4 -bn script.sh # Format in place (4-space indent)
shfmt -d -i 4 script.sh # Check only (diff output)
shellcheck *.sh # Lint
shfmt -d -i 4 *.sh # Check formatting
bats test/ # Run tests
bash -n script.sh # Syntax check (no execution)
For detailed patterns and examples, see:
development
Zig language guardrails, patterns, and best practices for AI-assisted development. Use when working with Zig files (.zig), build.zig, or when the user mentions Zig. Provides comptime patterns, allocator conventions, C interop guidelines, and testing standards specific to this project's coding standards.
tools
WordPress framework guardrails, patterns, and best practices for AI-assisted development. Use when working with WordPress projects, or when the user mentions WordPress. Provides theme development, plugin architecture, REST API, blocks, and security guidelines.
tools
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs. Use when testing web apps, automating browser interactions, or debugging frontend issues.
tools
Suite of tools for creating elaborate, multi-component web applications using modern frontend technologies (React, Tailwind CSS, shadcn/ui). Use for complex projects requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX pages.