6

I have a build script that executes a long command that produces lots of output which went like this:

./compile

In order to troubleshoot compilation performance, I want to use ts (from moreutils) which prefixes each output line with a timestamp. So I updated my script like this:

bash -c "./compile | ts '[%Y-%m-%d %H:%M:%S]'"

This works, but now the exit value is always 0, event when compile fails (I think, because ts exits without an error).

How can I update my script to return compile's exit code while using ts?

BoD
  • 163

2 Answers2

11

Since you’re using Bash, you can use its $PIPESTATUS which is an array containing the different exit codes from the commands in a pipeline:

bash -c './compile | ts "[%Y-%m-%d %H:%M:%S]"; exit "${PIPESTATUS[0]}"'

zsh has a similar feature but uses the $pipestatus array instead (also remember zsh arrays are numbered from 1, not 0).

Stephen Kitt
  • 434,908
5

You can use the pipefail option which is supported by a few shells including bash, ksh93, zsh, mksh, yash and busybox ash (and will be added to the specification of sh in the next major version of POSIX) and causes the exit status of a pipeline to be that of the right-most failing command.

For instance, the exit status of (exit 3) | (exit 4) | (exit 0) would be 4.

bash -o pipefail -c "./compile | ts '[%Y-%m-%d %H:%M:%S]'"

Would return with the exit status of ./compile unless ts itself fails.