Piping command output to tee but also save exit code of command
BashShellPipeShTeeBash Problem Overview
I have a shell script in which I wrap a command (mvn clean install), to redirect the output to a logfile.
#!/bin/bash
...
mvn clean install $@ | tee $logfile
echo $? # Does not show the return code of mvn clean install
Now if mvn clean install
fails with an error, I want my wrapper shell script also fail with that error. But since I'm piping all the output to tee, I cannot access the return code of mvn clean install
, so when I access $?
afterwards, it's always 0 (since tee successes).
I tried letting the command write the error output to a separate file and checking that afterwards, but the error output of mvn is always empty (seems like it only writes to stdout).
How can I preserve the return code of mvn clean install
but still piping the output to a logfile?
Bash Solutions
Solution 1 - Bash
You can set the pipefail
shell option option on to get the behavior you want.
From the Bash Reference Manual:
> The exit status of a pipeline is the exit status of the last command
> in the pipeline, unless the pipefail
option is enabled (see The Set Builtin).
> If pipefail
is enabled, the pipeline's return status is the
> value of the last (rightmost) command to exit with a non-zero status,
> or zero if all commands exit successfully.
Example:
$ false | tee /dev/null ; echo $?
0
$ set -o pipefail
$ false | tee /dev/null ; echo $?
1
To restore the original pipe setting:
$ set +o pipefail
Solution 2 - Bash
Since you're running bash
, you can use its $PIPESTATUS variable instead of $?
:
mvn clean install $@ | tee $logfile
echo ${PIPESTATUS[0]}
Solution 3 - Bash
You could run the mvn command and cache the exit code... I use the "false" command for my example.
$ { false ; echo $? > /tmp/false.status ; } | tee $logfile
$ cat /tmp/false.status
1
That way you can use the status file content to make further decisions.
I'm curious now whether there is a more eloquent way to accomplish this.
Solution 4 - Bash
Workaround (note: a perfer @Frederic's solution):
f=`mktemp`
(mvn clean install $@; echo $?>$f) | tee $logfile
e=`cat $f` #error in variable e
rm $f