Bash¶
Shell scripts are the glue of infrastructure — and the source of some of the most insidious production bugs. An unquoted variable, a missing set -e, a rogue eval — these cause outages. These 14 principles encode defensive shell scripting practices from the Google Shell Style Guide and ShellCheck community.
Optional External Tool Augmentation¶
Consent-first external tooling
External tool execution is optional and disabled by default. Use
--enable-external-tools (CLI) or enable_external_tools=true (MCP)
to opt in. Missing tools should return recommendations; no automatic
installs occur during analysis.
| Tool | Default invocation | Output |
|---|---|---|
shellcheck |
shellcheck - -f json |
JSON |
Zen Principles¶
14 principles across 10 categories, drawn from Google Shell Style Guide.
Correctness · 2 principles Error Handling · 2 principles Idioms · 1 principle Immutability · 1 principle Organization · 1 principle Readability · 2 principles Robustness · 2 principles Scope · 1 principle Security · 1 principle Usability · 1 principle
| Rule ID | Principle | Category | Severity | Dogma |
|---|---|---|---|---|
bash-001 |
Always use set -euo pipefail | Error Handling | 9 | ZEN-FAIL-FAST |
bash-002 |
Quote all variables | Correctness | 8 | ZEN-EXPLICIT-INTENT |
bash-003 |
Use [[ ]] over [ ] | Idioms | 7 | ZEN-RIGHT-ABSTRACTION |
bash-004 |
Use $() over backticks | Readability | 6 | ZEN-UNAMBIGUOUS-NAME, ZEN-RETURN-EARLY |
bash-005 |
Check command exit codes | Error Handling | 8 | ZEN-FAIL-FAST |
bash-006 |
Use functions for reusable code | Organization | 6 | ZEN-STRICT-FENCES |
bash-007 |
Use local variables in functions | Scope | 7 | ZEN-STRICT-FENCES |
bash-008 |
Avoid eval | Security | 9 | ZEN-STRICT-FENCES |
bash-009 |
Use readonly for constants | Immutability | 6 | ZEN-VISIBLE-STATE, ZEN-EXPLICIT-INTENT |
bash-010 |
Validate input and arguments | Robustness | 8 | ZEN-FAIL-FAST |
bash-011 |
Use meaningful variable names | Readability | 7 | ZEN-UNAMBIGUOUS-NAME |
bash-012 |
Handle signals properly | Robustness | 7 | ZEN-FAIL-FAST |
bash-013 |
Use arrays instead of string splitting | Correctness | 7 | ZEN-EXPLICIT-INTENT |
bash-014 |
Include usage information | Usability | 6 | ZEN-UNAMBIGUOUS-NAME |
bash-001 — Always use set -euo pipefail
Enable strict error handling at script start
Universal Dogmas: ZEN-FAIL-FAST
Common Violations:
- Scripts without set -e
- Not using set -u for undefined variables
- Not using set -o pipefail
- Missing error handling
Detectable Patterns:
#!/bin/bash without set -euo pipefail
Recommended Fix
set -euo pipefail at beginning of script
bash-002 — Quote all variables
Always quote variable expansions to prevent word splitting
Universal Dogmas: ZEN-EXPLICIT-INTENT
Common Violations:
- Unquoted $variable
- Unquoted ${variable}
- Unquoted command substitutions
- Unquoted array expansions
Detectable Patterns:
$variable without quotes$(command) without quotes
Recommended Fix
"\(variable" or "\)"
bash-003 — Use [[ ]] over [ ]
Prefer [[ ]] for conditional expressions
Universal Dogmas: ZEN-RIGHT-ABSTRACTION
Common Violations:
- Using [ ] for tests
- Not using [[ ]] for string comparisons
- Using test command
Detectable Patterns:
[ condition ]test condition
Recommended Fix
[[ condition ]]
bash-004 — Use $() over backticks
Prefer $() for command substitution
Universal Dogmas: ZEN-UNAMBIGUOUS-NAME, ZEN-RETURN-EARLY
Common Violations:
- Using backticks
command - Nested backticks
- Hard to read command substitution
Detectable Patterns:
command
Recommended Fix
$(command)
bash-005 — Check command exit codes
Always verify command success
Universal Dogmas: ZEN-FAIL-FAST
Common Violations:
- Not checking $? after commands
- Ignoring command failures
- Not using || or && for error handling
Detectable Patterns:
!$?
Recommended Fix
if ! command; then ... fi or command || handle_error
bash-006 — Use functions for reusable code
Extract repeated code into functions
Universal Dogmas: ZEN-STRICT-FENCES
Common Violations:
- Duplicated code blocks
- Long scripts without functions
- No code organization
Thresholds:
| Parameter | Default |
|---|---|
max_script_length_without_functions |
50 |
bash-007 — Use local variables in functions
Declare function variables as local
Universal Dogmas: ZEN-STRICT-FENCES
Common Violations:
- Function variables without local
- Global variable pollution
- Variable scope leakage
Detectable Patterns:
!local
bash-008 — Avoid eval
Don't use eval except when absolutely necessary
Universal Dogmas: ZEN-STRICT-FENCES
Common Violations:
- eval usage
- Constructing code from user input
- Security vulnerabilities
Detectable Patterns:
eval
bash-009 — Use readonly for constants
Mark constants as readonly
Universal Dogmas: ZEN-VISIBLE-STATE, ZEN-EXPLICIT-INTENT
Common Violations:
- Constants without readonly
- Magic values not in constants
- Mutable configuration values
Detectable Patterns:
!readonly
bash-010 — Validate input and arguments
Check script arguments and user input
Universal Dogmas: ZEN-FAIL-FAST
Common Violations:
- No argument count validation
- Not checking for required arguments
- No input sanitization
- Missing usage information
Detectable Patterns:
!$#
bash-011 — Use meaningful variable names
Avoid single-letter or cryptic names
Universal Dogmas: ZEN-UNAMBIGUOUS-NAME
Common Violations:
- Single letter variables (except i, j in loops)
- Abbreviations without context
- Unclear variable names
Thresholds:
| Parameter | Default |
|---|---|
min_variable_name_length |
3 |
bash-012 — Handle signals properly
Use trap for cleanup and signal handling
Universal Dogmas: ZEN-FAIL-FAST
Common Violations:
- No trap for cleanup
- Temporary files not cleaned up
- Missing EXIT trap
- No interrupt handling
Detectable Patterns:
!trap
Recommended Fix
trap cleanup EXIT INT TERM
bash-013 — Use arrays instead of string splitting
Store lists in arrays, not space-separated strings
Universal Dogmas: ZEN-EXPLICIT-INTENT
Common Violations:
- Splitting strings on spaces
- Not using arrays for lists
- Improper iteration over items
Detectable Patterns:
IFS=for item in $
Recommended Fix
array=(item1 item2); for item in "${array[@]}"
bash-014 — Include usage information
Provide help text and usage examples
Universal Dogmas: ZEN-UNAMBIGUOUS-NAME
Common Violations:
- Scripts without usage function
- No help flag (-h/--help)
- Missing documentation
Detectable Patterns:
!usage
Detector Catalog¶
Correctness¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| BashArrayUsageDetector | Detect IFS-based string splitting used instead of proper Bash arrays | bash-013 |
| BashQuoteVariablesDetector | Detect unquoted variable expansions that cause word-splitting bugs | bash-002 |
Error Handling¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| BashExitCodeChecksDetector | Detect external commands whose exit codes are silently ignored | bash-005 |
| BashStrictModeDetector | Detect scripts missing the unofficial Bash strict mode header | bash-001 |
Idioms¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| BashDoubleBracketsDetector | Detect single-bracket [ ] test expressions that should use [[ ]] |
bash-003 |
Immutability¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| BashReadonlyConstantsDetector | Detect ALL_CAPS assignments that are not declared readonly |
bash-009 |
Organization¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| BashFunctionUsageDetector | Detect long scripts that lack function decomposition | bash-006 |
Readability¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| BashMeaningfulNamesDetector | Detect overly short or cryptic variable names in shell scripts | bash-011 |
| BashCommandSubstitutionDetector | Detect legacy backtick command substitution syntax | bash-004 |
Robustness¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| BashArgumentValidationDetector | Detect scripts that use positional arguments without validation | bash-010 |
| BashSignalHandlingDetector | Detect scripts that lack trap handlers for cleanup on exit or signals |
bash-012 |
Scope¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| BashLocalVariablesDetector | Detect function-scoped variables missing the local keyword |
bash-007 |
Security¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| BashEvalUsageDetector | Detect usage of eval which enables code injection attacks |
bash-008 |
Usability¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| BashUsageInfoDetector | Detect scripts lacking a usage function or --help/-h flag |
bash-014 |
Principle → Detector Wiring
%%{init: {"theme": "base", "flowchart": {"useMaxWidth": false, "htmlLabels": true, "nodeSpacing": 40, "rankSpacing": 60}}}%%
graph TD
bash_001["bash-001<br/>Always use set -euo pipef..."]
bash_002["bash-002<br/>Quote all variables"]
bash_003["bash-003<br/>Use [[ ]] over [ ]"]
bash_004["bash-004<br/>Use $() over backticks"]
bash_005["bash-005<br/>Check command exit codes"]
bash_006["bash-006<br/>Use functions for reusabl..."]
bash_007["bash-007<br/>Use local variables in fu..."]
bash_008["bash-008<br/>Avoid eval"]
bash_009["bash-009<br/>Use readonly for constant..."]
bash_010["bash-010<br/>Validate input and argume..."]
bash_011["bash-011<br/>Use meaningful variable n..."]
bash_012["bash-012<br/>Handle signals properly"]
bash_013["bash-013<br/>Use arrays instead of str..."]
bash_014["bash-014<br/>Include usage information"]
det_BashArgumentValidationDetector["Bash Argument<br/>Validation"]
bash_010 --> det_BashArgumentValidationDetector
det_BashArrayUsageDetector["Bash Array<br/>Usage"]
bash_013 --> det_BashArrayUsageDetector
det_BashCommandSubstitutionDetector["Bash Command<br/>Substitution"]
bash_004 --> det_BashCommandSubstitutionDetector
det_BashDoubleBracketsDetector["Bash Double<br/>Brackets"]
bash_003 --> det_BashDoubleBracketsDetector
det_BashEvalUsageDetector["Bash Eval<br/>Usage"]
bash_008 --> det_BashEvalUsageDetector
det_BashExitCodeChecksDetector["Bash Exit<br/>Code Checks"]
bash_005 --> det_BashExitCodeChecksDetector
det_BashFunctionUsageDetector["Bash Function<br/>Usage"]
bash_006 --> det_BashFunctionUsageDetector
det_BashLocalVariablesDetector["Bash Local<br/>Variables"]
bash_007 --> det_BashLocalVariablesDetector
det_BashMeaningfulNamesDetector["Bash Meaningful<br/>Names"]
bash_011 --> det_BashMeaningfulNamesDetector
det_BashQuoteVariablesDetector["Bash Quote<br/>Variables"]
bash_002 --> det_BashQuoteVariablesDetector
det_BashReadonlyConstantsDetector["Bash Readonly<br/>Constants"]
bash_009 --> det_BashReadonlyConstantsDetector
det_BashSignalHandlingDetector["Bash Signal<br/>Handling"]
bash_012 --> det_BashSignalHandlingDetector
det_BashStrictModeDetector["Bash Strict<br/>Mode"]
bash_001 --> det_BashStrictModeDetector
det_BashUsageInfoDetector["Bash Usage<br/>Info"]
bash_014 --> det_BashUsageInfoDetector
Detector Class Hierarchy
%%{init: {"theme": "base"}}%%
classDiagram
direction TB
class ViolationDetector {
<<abstract>>
+detect(context, config)
}
class det_01["Bash Argument Validation"]
ViolationDetector <|-- det_01
class det_02["Bash Array Usage"]
ViolationDetector <|-- det_02
class det_03["Bash Command Substitution"]
ViolationDetector <|-- det_03
class det_04["Bash Double Brackets"]
ViolationDetector <|-- det_04
class det_05["Bash Eval Usage"]
ViolationDetector <|-- det_05
class det_06["Bash Exit Code Checks"]
ViolationDetector <|-- det_06
class det_07["Bash Function Usage"]
ViolationDetector <|-- det_07
class det_08["Bash Local Variables"]
ViolationDetector <|-- det_08
class det_09["Bash Meaningful Names"]
ViolationDetector <|-- det_09
class det_10["Bash Quote Variables"]
ViolationDetector <|-- det_10
class det_11["Bash Readonly Constants"]
ViolationDetector <|-- det_11
class det_12["Bash Signal Handling"]
ViolationDetector <|-- det_12
class det_13["Bash Strict Mode"]
ViolationDetector <|-- det_13
class det_14["Bash Usage Info"]
ViolationDetector <|-- det_14
Analysis Pipeline
%%{init: {"theme": "base", "flowchart": {"useMaxWidth": false, "htmlLabels": true, "nodeSpacing": 50, "rankSpacing": 70}}}%%
flowchart TD
Source(["Source Code"]) --> Parse["Parse & Tokenize"]
Parse --> Metrics["Compute Metrics"]
Metrics --> Pipeline{"14 Detectors"}
Pipeline --> Collect["Aggregate Violations"]
Collect --> Result(["AnalysisResult<br/>14 principles"])
Analysis States
%%{init: {"theme": "base"}}%%
stateDiagram-v2
[*] --> Ready
Ready --> Parsing : analyze(code)
Parsing --> Computing : AST ready
Computing --> Detecting : metrics ready
Detecting --> Reporting : 14 detectors run
Reporting --> [*] : AnalysisResult
Parsing --> Reporting : parse error (best-effort)
Configuration¶
See Also¶
- PowerShell — Object-pipeline shell with different idioms
- Configuration — Per-language pipeline overrides
- Understanding Violations — Severity scale reference