output both stderr and stdout on console and store them in a file at same time

21,578

Solution 1

  1. how to just output stdout and catch stderr into file?(I tried ./test|tee 2>log, but doesn't work)
$ ./test 2>log
OUT!
$ cat log
ERR!
  1. how to just output both and catch stderr into file?
$ ./test 2>&1 >/dev/tty | tee log
OUT!
ERR!
$ cat log
ERR!

If this expression was to be part of a larger pipeline, then you may want to avoid the use of /dev/tty. One way to do that is to swap stdout and stderr. To do this swap, we need to create a third file handle like so:

$ exec 3>&1; ./test 2>&1 1>&3 | tee log; exec 3>&-
OUT!
ERR!
$ cat log
ERR!

The first statement, exec 3>&1, assigns file handle 3 to the current stdout (whatever that might be). Then, ./test 2>&1 1>&3 | tee log pipes stderr to the tee command while sending stdout to file handle 3. Finally, for good housekeeping, exec 3>&- closes file handle 3.

Additional notes and comments

Regarding:

I can output stderr and catch stdout into log file by:

$./test | tee 1>log
ERR!
$cat log 
OUT!

That can be simplified to:

$ ./test >log
ERR!
$ cat log
OUT!

Also, regarding:

I can output nothing but catch all stdout and stderro into log file by:

$ ./test 2>&1| tee 1>log
$ cat log 
OUT!
ERR!

That can be simplified to:

$ ./test >log 2>&1
$ cat log
OUT!
ERR!

Or, with bash, but not POSIX shell, a still simpler form is possible:

$ ./test &>log
$ cat log
OUT!
ERR!

Solution 2

Shells redirections should be fairly enough. First, to redirect stderr to a file...

$ ./test 2> myfile.txt

Here, stdout remains the screen, since it wasn't redirected. myfile.txt will contain ERR.

Then, if you want to output both, and still catch stderr into a file, you'll probably have to go in two steps with a little command substitution...

$ ./test 2> >(tee myfile.txt >&2)

This will send the error stream to the tee process, which will reprint them. stdout remains untouched. For more information, have a look at this Stack Overflow question.

Similarly, if you want to catch stdout into a file, and leave stderr untouched...

$ ./test > >(tee myfile.txt)
Share:
21,578

Related videos on Youtube

How Chen
Author by

How Chen

MSc in RF signal processing and design, experienced developer of linux driver, RF de/modulation driver, embedded system development, M2M module development Specialties Mathematics Modeling, Signal Processing, Linux system development, Linux driver, Digital TV

Updated on September 18, 2022

Comments

  • How Chen
    How Chen almost 2 years

    may I output both stdout and stderr on console screen and store one of them into a log file?

    I write a test shell script:

    #!/bin/sh
    
    echo OUT! >&1
    echo ERR! >&2
    

    I can output both of them on screen just by run the script:

    $./test 
    OUT!
    ERR!
    

    I can output stderr and catch stdout into log file by:

    $./test | tee 1>log
    ERR!
    
    $cat log 
    OUT!
    

    I can output nothing but catch all stdout and stderro into log file by:

    $./test 2>&1| tee 1>log
    
    $cat log 
    OUT!
    ERR!
    

    I can output both of stdout and stderr and catch all of them into a log file by:

    $./test 2>&1 | tee log
    OUT!
    ERR!
    
    $cat log 
    OUT!
    ERR!
    

    I can output both can catch stdout into log file by:

    $./test | tee 2>&1 log
    ERR!
    OUT!
    
    $cat log 
    OUT!
    

    My questions are:

    1. how to just output stdout and catch stderr into file?(I tried ./test|tee 2>log, but doesn't work)
    2. how to just output both and catch stderr into file?
  • ctrl-alt-delor
    ctrl-alt-delor over 9 years
    +1 for not involving tty. It is more flexible if we want to use it in a pipeline.