
Shell Review
Review bash pipelines and CI scripts so failures are not hidden behind the last command’s exit code.
Install
npx skills add https://github.com/athola/claude-night-market --skill shell-reviewWhat is this skill?
- Documents why pipelines default to the last command’s exit code and how that masks make or test failures
- Three fixes: set -o pipefail, capture output with separate exit_code, or Bash PIPESTATUS[0]
- Includes copy-paste detection greps for pipelines piped to grep, head, and tail
- Shows anti-pattern: if (make typecheck 2>&1 | grep -v "^make\[") that prints Passed when make failed
- Parent module exit-codes under pensive:shell-review for error-handling and pipefail tags
Adoption & trust: 1 installs on skills.sh; 304 GitHub stars; 3/3 security scanners passed (skills.sh audits); trending (+100% hot-view momentum).
Recommended Skills
Improve Codebase Architecturemattpocock/skills
Zoom Outmattpocock/skills
Caveman Reviewjuliusbrussee/caveman
Requesting Code Reviewobra/superpowers
Receiving Code Reviewobra/superpowers
Request Refactor Planmattpocock/skills
Journey fit
Primary fit
Shell review belongs on the Ship shelf because it guards release and CI scripts where a false green is a production incident. Canonical fit is review: you audit existing shell and pipeline patterns before merge or deploy, not while authoring features.
Common Questions / FAQ
Is Shell Review safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Shell Review
# Exit Code Patterns ## Critical: Pipeline Exit Codes The default bash behavior is that a pipeline's exit code equals the **last** command's exit code. This masks failures: ```bash # BAD - grep always succeeds if it finds lines, hiding make failure if (make typecheck 2>&1 | grep -v "^make\["); then echo "Passed" # WRONG - runs even when make fails! fi ``` ### Fix 1: Use pipefail ```bash set -o pipefail # Now pipeline fails if ANY command fails if make typecheck 2>&1 | grep -v "^make\["; then echo "Passed" fi ``` ### Fix 2: Capture Output and Exit Code Separately ```bash # Capture output, preserve exit code local output local exit_code=0 output=$(make typecheck 2>&1) || exit_code=$? # Filter output for display echo "$output" | grep -v "^make\[" || true # Check actual exit code if [ "$exit_code" -eq 0 ]; then echo "Passed" else echo "Failed" return 1 fi ``` ### Fix 3: Use PIPESTATUS (Bash-specific) ```bash make typecheck 2>&1 | grep -v "^make\[" if [ "${PIPESTATUS[0]}" -ne 0 ]; then echo "Make failed" exit 1 fi ``` ## Detection Commands Find pipeline patterns that may mask failures: ```bash # Commands piped to grep/head/tail (common culprits) grep -n "| grep" scripts/*.sh grep -n "| head" scripts/*.sh grep -n "| tail" scripts/*.sh # Pipelines in if conditions grep -n "if.*|" scripts/*.sh # Subshells with pipelines grep -n "\$(.*|" scripts/*.sh ``` ## set -e Pitfalls `set -e` (exit on error) has exceptions that can surprise: ```bash set -e # These do NOT trigger exit: cmd || true # Explicit fallback if cmd; then ... # Part of condition cmd && other # Part of AND/OR list while cmd; do ... # Loop condition # This DOES trigger exit: cmd # Standalone command that fails ``` ## Subshell Exit Codes ```bash # BAD - subshell exit code lost (cd /tmp && failing_command) echo "This runs even if failing_command failed" # GOOD - check subshell result if ! (cd /tmp && failing_command); then echo "Failed" exit 1 fi # GOOD - use || to handle failure (cd /tmp && failing_command) || { echo "Failed"; exit 1; } ``` ## Common Patterns to Flag | Pattern | Risk | Fix | |---------|------|-----| | `cmd \| grep` in `if` | Exit code from grep | pipefail or capture | | `$(cmd \| filter)` | Exit code from filter | PIPESTATUS or capture | | `cmd \| head -1` | Loses cmd failure | pipefail | | `cmd 2>&1 \| tee log` | May hide failure | pipefail | | `set -e` and pipes | Inconsistent behavior | Explicit checks | --- parent_skill: pensive:shell-review module: portability description: POSIX vs Bash compatibility and cross-platform considerations tags: [posix, bash, portability, cross-platform] --- # Shell Portability ## Shebang Lines ```bash #!/bin/sh # POSIX shell (most portable) #!/bin/bash # Bash (most features) #!/usr/bin/env bash # Bash via env (handles non-standard paths) ``` If using Bash features, use `#!/usr/bin/env bash` for portability across systems where bash may not be at `/bin/bash`. ## Bash-Only Features These require `#!/bin/bash` or `#!/usr/bin/env bash`: | Feature | Bash | POSIX Alternative | |---------|------|-------------------| | `[[ ... ]]` | Yes | `[ ... ]` | | `(( ... ))` | Yes | `$(( ... ))` or `[ ... ]` | | Arrays | Yes | Use files or positional params | | `${var:offset:len}` | Yes | `expr` or external tools | | `${var//pat/rep}` | Yes | `sed` | | `<<<` here-string | Yes | `echo "$var" \|` | | `<(cmd)` process sub | Yes | Temp files or pipes | | `source file` | Yes | `. file` | | `function name { }` | Yes | `name() { }` | | `local -n` nameref | Bash 4.3+ | Workarounds | ## Detection Commands ```bash # Find Bash-isms in #!/bin/sh scripts grep -l "^#!/bin/sh" scripts/*.sh | while read f; do # Check for [[ ]] grep -n