Terminal · foundation
Conditional command execution
The shell operators && and || conditionally execute a following pipeline according to the preceding pipeline's exit status, with left associativity and short-circuit evaluation.
Why it matters
They express success-dependent steps and fallback behavior compactly, but ambiguous chains can perform actions the author did not intend.
Mental model
How to reason about conditional command execution
For A && B, run B only when A returns zero; for A || B, run B only when A returns nonzero, then continue evaluating a chain from left to right.
Analogy
They act like guarded doors: one opens on a successful badge check and the other opens only when that check is rejected.
Examples
See the boundary, not just the happy path
Worked example · Deploy only a tested build
build && test && deployEach next stage runs only if every earlier stage in the left-associative chain returned zero.
Worked example · Provide a fallback
load_cache || fetch_remotefetch_remote runs only if load_cache returns nonzero, so the command's status contract defines what triggers the fallback.
Avoid · False ternary idiom
condition && success_action || failure_actionIf success_action itself returns nonzero, failure_action also runs; an explicit if statement expresses two exclusive branches safely.
Common mistakes
Misconceptions to remove early
Reading && as a data operator
It branches on pipeline exit status; it does not combine output or pass values between commands.
Assuming success means the intended business result
Zero means whatever the command documents as success, so predicates and comparison tools may need command-specific interpretation.
Quick check
Can you predict the result?
1. When does cleanup || report_failure run report_failure?
- • When cleanup returns a nonzero exit status
- • When cleanup prints to stderr
- • Always after cleanup
2. Why is A && B || C not a dependable shell ternary expression?
Keep building