Stop your subshells from swallowing exit codes when you pipe them
Technical Briefing | 8/10/2026
You spend all morning writing a robust pipeline, chaining commands with pipes to process your logs. Then you add an if statement to check the exit status, and it fails open. Or worse, it silently ignores the fact that the first command in the pipe crashed hard. I have seen this blow up CI/CD pipelines more times than I care to admit.
The pipefail problem
By default, a shell pipe only cares about the exit status of the final command. If you run grep | sed | awk, and the grep hits a file that doesn’t exist, the shell will blithely report that the entire operation succeeded if the awk command finished correctly. That is a trap. You need to enable the pipefail option, but remember that it is a shell-specific setting and often gets lost when you call subshells or scripts.
set -o pipefail
cat data.log | process_data | save_to_db
if [ $? -eq 0 ]; then echo success; else echo failed; fi
- Enable pipefail at the top of every script that chains commands
- Avoid backticks for command substitution as they swallow exit codes entirely
- Use local declarations for settings to prevent global scope leakage
- Verify your logic with intentionally broken inputs before merging
If you are running bash inside a container or a specialized build agent, don’t assume the environment has pipefail enabled for you. Explicitly set it. And if you are nesting your logic inside parentheses to keep your namespace clean, keep in mind that those subshells act as their own environment, meaning your top-level settings won’t always propagate down. Check your exit codes like you actually care if your scripts work.
