核心 · Key Idea
In one line: bash scripts are quick to write but full of footguns. The trio set -euo pipefail + always-quote variables + shellcheck eliminates 90 % of hidden bugs.
What it is#
Minimal viable script:
#!/usr/bin/env bash
set -euo pipefail
NAME="${1:-world}"
echo "Hello, $NAME"
for f in *.log; do
echo "processing $f"
gzip "$f"
done#!/usr/bin/env bash is more portable than #!/bin/bash (uses PATH).
Analogy#
打个比方 · Analogy
bash is glue language — it sticks small tools together. Don't use it for complex logic — once a script crosses 100 lines, switch to Python / Go.
Key concepts#
shebang#!
First line tells the kernel which interpreter to use.
set -eerrexit
Exit immediately on any non-zero return.
set -unounset
Error on unset variables (prevents `rm -rf $UNDEFINED/`).
set -o pipefailpipefail
Any failure in a pipeline fails the whole pipeline (default only checks the last command).
trapSignal / exit hook
`trap cleanup EXIT` — clean up temp files before the script exits.
$1 / $@ / $#Positional args
$1 first arg; $@ all; $# count.
$(cmd)Command substitution
Embeds cmd output into a string (clearer than backticks).
Common template#
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
log() { echo "[$(date +%T)] $*" >&2; }
cleanup() {
rm -f "$tmp"
}
trap cleanup EXIT
tmp=$(mktemp)
log "starting"
# Bail loudly when required env vars are missing:
: "${API_KEY:?need API_KEY}"
# Safe quoting — paths with spaces are fine
for f in "$dir"/*.log; do
[[ -e "$f" ]] || continue
gzip "$f"
done
log "done"Debugging recipe#
shellcheck is mandatory — catches unquoted vars, wrong ==, [ ] vs [[ ]] issues, etc.
Practical notes#
- Always quote variables:
"$var"— strings with spaces / globs won't split into multiple args. - Prefer
[[ ]]over[ ]: modern bash test, safe even without quotes. - Use
${var:-default}/${var:?msg}for fallback / required-arg checks. - Don't parse
ls— usefor f in *orfind ... -print0 | xargs -0. - Don't ignore errors:
cmd || die "msg",if ! cmd; then ... fi. - Temp files via mktemp — avoids race conditions and shared
/tmpcollisions. - Past 100 lines → Python. Picking bash for complex logic is usually the wrong language choice.
Easy confusions#
bash script
File + shebang + `set -euo pipefail`.
Reusable, CI-friendly.
Reusable, CI-friendly.
ad-hoc command
One-shot pipeline `cmd1 | cmd2 | cmd3`.
Fine for debugging — **don't paste it into prod**.
Fine for debugging — **don't paste it into prod**.