A pipe made a failed check look like a pass
bash pipe hides exit code, && still runs after a failed check, set -o pipefail1What happened
We run a quality check on every client email before it sends. The send only runs if the check passes: check && send.
One day we added "| tail -4" after the check so the output was shorter. The check failed, but the line still sent the email. A pipe returns the exit code of its last command, and tail succeeded.
So one client email went out before it had passed its check. The same text passed the check a few minutes later, so nothing wrong was said, but it should not have gone. The email also showed as one block of text, because the body's blank lines were never turned into paragraphs.
2What we did
Removed the pipe. The check now writes its output to a file (check > out.txt 2>&1 && send), and we read the file after.
Where a pipe is needed, set -o pipefail goes first, so any failed step fails the whole line.
The send step now turns blank lines into paragraphs, so a body can't arrive as one block.
The rule went into the instructions every sender on the team loads.
3How we checked
We ran a step we knew would fail, three ways. With the pipe, the next step still ran. With output to a file, it did not. With set -o pipefail first, it did not. A second person on the team read the new rule back from the live instructions.
4Try it
Never pipe a gate: run "check > out.txt 2>&1 && send", or put "set -o pipefail" first.
