Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write stderr to a file while using "tee" with a pipe?

Tags:

linux

bash

unix

tee

I know how to use tee to write the output (standard output) of aaa.sh to bbb.out, while still displaying it in the terminal:

./aaa.sh | tee bbb.out 

How would I now also write standard error to a file named ccc.out, while still having it displayed?

like image 490
jparanich Avatar asked Mar 28 '09 01:03

jparanich


People also ask

Does tee catch stderr?

But how to make tee catch the stderr only? You can make use of “process substitution” ( >(...) ) to creates a FIFO to catch the STDERR and pass it to tee . The “world” is not to the STDOUT anymore.

How do you pipe a stderr to a file?

Redirecting stderr to a file:Use the “2>” operator for redirecting the stderr to a file. We can combine the execution for stderr and stdout in a single redirection command. In the below-given example, the error messages will be stored in “error. txt,” where “output.

Is stderr piped?

According to "Linux: The Complete Reference 6th Edition" (pg. 44), you can pipe only STDERR using the |& redirection symbols. Presumably, only the lines printed to STDERR will be indented.


2 Answers

I'm assuming you want to still see STDERR and STDOUT on the terminal. You could go for Josh Kelley's answer, but I find keeping a tail around in the background which outputs your log file very hackish and cludgy. Notice how you need to keep an exra FD and do cleanup afterward by killing it and technically should be doing that in a trap '...' EXIT.

There is a better way to do this, and you've already discovered it: tee.

Only, instead of just using it for your stdout, have a tee for stdout and one for stderr. How will you accomplish this? Process substitution and file redirection:

command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2) 

Let's split it up and explain:

> >(..) 

>(...) (process substitution) creates a FIFO and lets tee listen on it. Then, it uses > (file redirection) to redirect the STDOUT of command to the FIFO that your first tee is listening on.

Same thing for the second:

2> >(tee -a stderr.log >&2) 

We use process substitution again to make a tee process that reads from STDIN and dumps it into stderr.log. tee outputs its input back on STDOUT, but since its input is our STDERR, we want to redirect tee's STDOUT to our STDERR again. Then we use file redirection to redirect command's STDERR to the FIFO's input (tee's STDIN).

See http://mywiki.wooledge.org/BashGuide/InputAndOutput

Process substitution is one of those really lovely things you get as a bonus of choosing bash as your shell as opposed to sh (POSIX or Bourne).


In sh, you'd have to do things manually:

out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$" mkfifo "$out" "$err" trap 'rm "$out" "$err"' EXIT tee -a stdout.log < "$out" & tee -a stderr.log < "$err" >&2 & command >"$out" 2>"$err" 
like image 98
lhunath Avatar answered Sep 30 '22 17:09

lhunath


Simply:

./aaa.sh 2>&1 | tee -a log 

This simply redirects standard error to standard output, so tee echoes both to log and to the screen. Maybe I'm missing something, because some of the other solutions seem really complicated.

Note: Since Bash version 4 you may use |& as an abbreviation for 2>&1 |:

./aaa.sh |& tee -a log 
like image 29
user542833 Avatar answered Sep 30 '22 19:09

user542833