bash: redirect stderr to file and stdout + stderr to screen

19,355

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.

Share:
19,355

Related videos on Youtube

linuxguy
Author by

linuxguy

Updated on September 18, 2022

Comments

  • linuxguy
    linuxguy over 1 year

    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.

  • linuxguy
    linuxguy over 7 years
    Great, that solve my issue!
  • Master DJon
    Master DJon over 6 years
    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".
  • Master DJon
    Master DJon over 6 years
  • x0a
    x0a over 5 years
    It works but I'm having trouble understanding how this doesn't cause recursion. 3 is redirected to stdout. But then stdout is redirected to &3?
  • icarus
    icarus over 5 years
    @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
    icarus over 5 years
    @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
  • x0a
    x0a over 5 years
    @icarus Ahh I see it now. So invoking the pipe replaces the original &1 with a reference to tee's stdin. And so we don't lose access to the original &1/stdout, we declare a "global" reference to it before we create the pipe (and call it &3). Awesome, thanks!
  • aviro
    aviro over 2 years
    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.