# Bash Gotchas ## `set -e` silently kills scripts with complex subshell pipelines `set -euo pipefail` can cause silent termination with no output when scripts use loops containing command substitutions, subshell calls, and pipelines. The script appears to produce no output and exits non-zero. For read-only/reporting tools, use `set -uo pipefail` without `-e` and handle errors explicitly. ## `grep` interprets option-like strings as flags `grep -qF "$var"` will fail if `$var` starts with `--` (e.g., `--dryrun`). Always use `--` to terminate option parsing: `grep -qF -- "$var"`. ## `local` keyword only works inside functions Using `local` in the main script body (e.g., inside a `for` loop that isn't wrapped in a function) causes `local: can only be used in a function`. Either wrap the loop in a function or omit `local`. ## `set -e` kills command substitution capturing non-zero exit codes `output=$(cmd)` where `cmd` exits non-zero will trigger `errexit` before `rc=$?` on the next line executes. Use `output=$(cmd) && rc=$? || rc=$?` or `output=$(cmd) || true` to safely capture output from commands expected to fail. ## `file` command marks shell scripts as "executable" The `file` command returns strings like "Bourne-Again shell script, Unicode text, UTF-8 text executable" for shell scripts. Grepping for `executable` to detect binaries will false-positive on text scripts. Instead, grep for `binary|image|archive` and additionally check that the output does NOT contain `text`.