Stop your subshells from swallowing exit codes during pipe failures
By Saket Jain Published Linux/Unix
Stop your subshells from swallowing exit codes during pipe failures
Technical Briefing | 7/30/2026
You spend half an hour writing a neat pipeline, thinking you’ve handled every edge case. Then it runs in production, fails halfway through, and the script just keeps moving along as if nothing happened. That’s because of how pipes interact with exit codes. Most people assume the script stops if one part fails, but that’s not how it works by default.
Why pipes are trickier than they look
When you chain commands like grep or sed, the shell only cares about the exit status of the final command in the pipeline. If your curl command at the start hits a 404 or your authentication token expires, the shell treats the whole line as a success. This bit me more than once back when I was starting out. You need to explicitly tell the shell to propagate failures across the entire chain.
set -o pipefail
cat data.log | grep "critical" | tee errors.txt
- pipefail forces the pipeline to return the status of the last command to exit with a non-zero code
- If all commands in the chain succeed, the pipeline will still return 0
- Check PIPESTATUS array if you need to know exactly which segment failed without stopping the script
Handling failure without losing context
While set -o pipefail is the right approach for most automation, it can be aggressive. Sometimes you actually want to ignore a failure from a specific part of the chain. If that happens, be explicit. Redirecting output or handling errors with an OR operator is often cleaner than debugging a script that silently corrupted your data because the pipeline lied about its exit status.
Keep this in your .bashrc or your global script templates. It’s a small change, but it’ll save you from one of the most frustrating classes of production bugs. Once you get used to seeing your scripts actually halt on failure, you’ll never want to go back.
