diff options
Diffstat (limited to 'languages/bash/claude/rules/bash.md')
| -rw-r--r-- | languages/bash/claude/rules/bash.md | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/languages/bash/claude/rules/bash.md b/languages/bash/claude/rules/bash.md new file mode 100644 index 0000000..042138a --- /dev/null +++ b/languages/bash/claude/rules/bash.md @@ -0,0 +1,83 @@ +# Bash Code Rules + +Applies to: `**/*.sh`, `**/*.bash`, and extensionless files with a `sh`/`bash` shebang + +Shell-specific style and structure. Pairs with `bash-testing.md` for tests and +the generic `verification.md` / `commits.md` rules. When in doubt, defer to +[ShellCheck](https://www.shellcheck.net/wiki/) (every SCxxxx code has a wiki +page explaining the fix) and Google's +[Shell Style Guide](https://google.github.io/styleguide/shellguide.html). + +## ShellCheck Is the Gate, Not a Suggestion + +The bundle's PostToolUse hook runs `shellcheck` on every edited shell file and +blocks on a violation; the pre-commit hook re-checks staged files. ShellCheck +catches the bugs that define shell: unquoted expansions that word-split, unset +variables, `[ ]` pitfalls, masked exit codes. Fix the finding rather than +silence it. When a warning is a genuine false positive, disable it narrowly with +a `# shellcheck disable=SCxxxx` directive on the line above and a comment saying +why, never a file-wide blanket disable. + +## The Header: Strict Mode + +Every script starts with `#!/usr/bin/env bash` and `set -euo pipefail`: + +- `-e` exits on an unhandled non-zero command. Handle the expected-failure cases + explicitly (`cmd || true`, an `if`, a `case`) so the exit is a real error. +- `-u` treats an unset variable as an error. Use `"${VAR:-default}"` for the + ones that are legitimately optional. +- `-o pipefail` makes a pipeline fail if any stage fails, not just the last. + +A script meant to be *sourced* (a library) skips `set -e` — it would change the +caller's shell. Libraries guard their own commands instead. + +## Quote Everything + +- Double-quote every expansion: `"$var"`, `"$@"`, `"${arr[@]}"`, + `"$(command)"`. Unquoted is the single largest source of shell bugs — a path + with a space becomes two arguments. +- `"$@"` (quoted) passes arguments through untouched; `$*` and unquoted `$@` + word-split. Use `"$@"` unless you specifically want the joined string. +- Loop over arrays and `find -print0 | while IFS= read -r -d ''`, never over + unquoted command substitution or `ls` output. + +## Test, Compare, Branch + +- Use `[[ ]]` for tests, not `[ ]` / `test`. `[[ ]]` doesn't word-split its + operands, supports `&&`/`||`/`=~`, and has fewer quoting traps. +- Arithmetic goes in `(( ))` or `$(( ))`, not `[ ]` with `-eq`. +- `$(command)`, never backticks — nests cleanly and reads better. +- Prefer `printf` over `echo` for anything but a fixed literal string; + `echo` mangles values that start with `-` or contain backslashes. + +## Functions and Scope + +- Declare function-local variables with `local`. A bare assignment in a + function writes a global and leaks across calls. +- `local var; var="$(cmd)"` on two lines when you need the command's exit + status: `local var="$(cmd)"` masks `cmd`'s exit code behind `local`'s. +- Keep functions focused. A function that fetches, parses, and writes is three + functions; the test difficulty in `bash-testing.md` is the tell. +- Put `main "$@"` at the bottom for a script with more than a couple of + functions, so definition order doesn't dictate execution order. + +## Robustness + +- `trap 'rm -rf "$tmpdir"' EXIT` right after creating a temp resource, so + cleanup runs on every exit path including errors. +- Make a temp file or dir with `mktemp` / `mktemp -d`, never a fixed + `/tmp/name` (race + collision). +- Check that a required command exists before the work: `command -v jq + >/dev/null || { echo "jq required" >&2; exit 1; }`. +- Never parse `ls` output and don't `cat` a file into a pipe you could read + directly. Glob, or use `find`, or read the file in place. + +## What Not to Do + +- Don't leave an expansion unquoted to "save a quote" — quote it. +- Don't use `[ ]` when `[[ ]]` is available, or backticks when `$()` is. +- Don't silence a ShellCheck warning file-wide to clear it; fix it or disable + the one code with a reason. +- Don't refactor surrounding code while fixing a bug — keep the diff scoped. +- Don't commit credentials or API keys — the pre-commit hook catches common + patterns but isn't a substitute for care. |
