20

I would like to save the stderr stream of a command into a log file but I also want to display the whole output (stdout + stderr) on the screen. How can I do this?

I only found the solution to display stdout + stderr to the console and redirect both streams to a file as well:

 foo | tee output.file

(https://stackoverflow.com/questions/418896/how-to-redirect-output-to-a-file-and-stdout)

But I only want to redirect stderr to the log file.

1

2 Answers 2

17

With a recent bash, you can use process substitution.

foo 2> >(tee stderr.txt)

This just sends stderr to a program running tee.

More portably

exec 3>&1 
foo 2>&1 >&3 | tee stderr.txt

This makes file descriptor 3 be a copy of the current stdout (i.e. the screen), then sets up the pipe and runs foo 2>&1 >&3. This sends the stderr of foo to the same place as the current stdout, which is the pipe, then sends the stdout to fd 3, the original output. The pipe feeds the original stderr of foo to tee, which saves it in a file and sends it to the screen.

7
  • Great, that solve my issue!
    – linuxguy
    Commented Dec 28, 2016 at 7:25
  • foo 2>&1 >&3 | tee stderr.txt is working as intended, but I would like to have both to a file and errors to an another. I tried multiple things but nothing do it. Do you have any suggestions? This way, it is easier to locate errors with the real execution by finding them in "both-file" from "error-file". Commented Jan 23, 2018 at 5:08
  • 1
    I found my answer: stackoverflow.com/a/45426547/214898 Commented Jan 23, 2018 at 5:16
  • 1
    @x0a Let me try and explain. The important thing to understand is the way the foo 2>&1 >&3 | tee stderr.txt is executed. The first thing that is handled is the |. To handle this the shell creates a pipe, and then forks to create 2 processes. One handles the foo 2>&1 >&3 and the other handles the tee stderr.txt. The first connects stdout to the pipe, and the second connects stdin to the pipe. ....
    – icarus
    Commented Dec 24, 2018 at 23:45
  • 1
    @x0a .... The first shell now does the redirections, left to right. So 2>&1 connects the stderr of what will be foo to the current stdout, i.e. the pipe, then >&1 redirects the stdout of what will become foo )which is currently pointing to the pipe) to the original stdout that was saved in 3
    – icarus
    Commented Dec 24, 2018 at 23:46
2

the best answer i could find: here

(cmd 2> >(tee /dev/stderr)) > log

it pipes both (stdout and stderr) to both (screen and file) and let you capture the error if used in inline condition ( if ) or successive inline commands.

ex:

$((curl "https://unix.stackexchange.com"  2> >(tee /dev/stderr)) >> logfile) && echo "some other commands if curl succeeds without error"

in other methods like for piping to tee like that ( | tee ...), the next command ( echo...) is executed whatever (curl) succeeds or fails, because it considers ( tee ) as the last command executed, not ( curl )

1
  • This works as long as your shell is originally yours, and you haven't performed su command on the way to get the shell. After su, the /dev/stderr (or out) is link to the tty that belongs to the original user, so the shell won't be able to open the file for writing.
    – aviro
    Commented Dec 9, 2021 at 7:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .