I want to execute a long running command in Bash, and both capture its exit status, and tee its output.
So I do this:
command | tee out.txt
ST=$?
The problem is that the variable ST captures the exit status of tee
and not of command. How can I solve this?
Note that command is long running and redirecting the output to a file to view it later is not a good solution for me.
In Ubuntu and Debian, you can
apt-get install moreutils
. This contains a utility calledmispipe
that returns the exit status of the first command in the pipe.The simplest way to do this in plain bash is to use process substitution instead of a pipeline. There are several differences, but they probably don't matter very much for your use case:
pipefail
option and thePIPESTATUS
variable are irrelevant to process substitution.With process substitution, bash just starts the process and forgets about it, it's not even visible in
jobs
.Mentioned differences aside,
consumer < <(producer)
andproducer | consumer
are essentially equivalent.If you want to flip which one is the "main" process, you just flip the commands and the direction of the substitution to
producer > >(consumer)
. In your case:Example:
As I said, there are differences from the pipe expression. The process may never stop running, unless it is sensitive to the pipe closing. In particular, it may keep writing things to your stdout, which may be confusing.
By combining
PIPESTATUS[0]
and the result of executing theexit
command in a subshell, you can directly access the return value of your initial command:command | tee ; ( exit ${PIPESTATUS[0]} )
Here's an example:
will give you:
return value: 1