How to make tee catch the stderr only in Linux?

I would like to make tee catch the stderr and log it into a file.

A brute force method by let tee listen on both stderr and stdout is okay like

cmd 2>&1 | tee -a log

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.

Lets take an example t.sh:

#!/bin/bash

echo hello
1>&2 echo world

It works as expected:

$ ./t.sh 
hello
world
$ ./t.sh >/dev/null
world
$ ./t.sh 2>/dev/null
hello

Now, let’s redirect the STDERR to tee:

$ ./t.sh 2> >(tee /tmp/log)
hello
$ world
cat /tmp/log 
world

tee prints to STDOUT by default. Let’s make it print to STDERR:

$ ./t.sh 2> >(tee /tmp/log >&2)
hello
world
$ cat /tmp/log 
world

Verify it:

$ (./t.sh 2> >(tee /tmp/log >&2) ) >/dev/null
world

The “world” is not to the STDOUT anymore.

Eric Ma

Eric is a systems guy. Eric is interested in building high-performance and scalable distributed systems and related technologies. The views or opinions expressed here are solely Eric's own and do not necessarily represent those of any third parties.

One comment:

  1. Thanks, it really helped.

    I’ve tried to make logging of STDOUT and STDERR to separate files, but also have STDERR output in the terminal. This is what I came up with.

    test-script.sh:
    “`
    #!/bin/bash

    echo ‘Regular stdout’
    1>&2 echo ‘Error!’
    “`

    Terminal:
    “`
    ./test-script.sh > file.log 2> >(tee file-error.log >&2)
    “`

    Output:
    “`
    Error!
    “`

    file.log:
    “`
    Regular stdout
    “`

    file-error.log:
    “`
    Error!
    “`

Leave a Reply

Your email address will not be published. Required fields are marked *