Shell Scripting
Write scripts that fail loudly and safely, not ones that silently do the wrong thing.
Start every script with a strict header
#!/usr/bin/env bash
set -euo pipefail # exit on error, error on unset var, fail a pipeline if any stage fails
IFS=$'\n\t'
Quoting & safety (the top source of bugs)
- Always quote expansions:
"$var","${arr[@]}","$(cmd)"— unquoted values word-split and glob. - Use
[[ ... ]]over[ ... ]for tests;(( ... ))for arithmetic. - Prefer
"$(cmd)"over backticks. Checkmkdir -p,rm -rfpaths twice. - Handle filenames with spaces/newlines:
find ... -print0 | xargs -0, orwhile IFS= read -r line.
Common patterns
# Args with defaults
name="${1:-world}"
# Loop over files safely
for f in ./*.log; do [[ -e "$f" ]] || continue; echo "$f"; done
# Trap cleanup on exit
tmp="$(mktemp)"; trap 'rm -f "$tmp"' EXIT
# Check a command exists
command -v jq >/dev/null 2>&1 || { echo "jq required" >&2; exit 1; }
Guidance
- Run
shellcheck script.shif available — it catches most real bugs. - Make scripts idempotent where possible; print what they're doing.
- Don't parse
lsoutput; glob or usefind. Don'tevaluntrusted input. - For anything beyond ~50 lines of logic, consider Python instead.