How to make tee catch the stderr only in Linux?

Posted on In QA

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 *