62

I wanted to know the difference between the following two commands

2>&1 > output.log 

and

2>&1 | tee output.log

I saw one of my colleague use second option to redirect. I know what 2>&1 does, my only question is what is the purpose of using tee where a simple redirection ">" operator can be used?

0

5 Answers 5

47

Looking at the two commands separately:

utility 2>&1 >output.log 

Here, since redirections are processed in a left-to-right manner, the standard error stream would first be redirected to wherever the standard output stream goes (possibly to the console), and then the standard output stream would be redirected to a file. The standard error stream would not be redirected to that file.

The visible effect of this would be that you get what's produced on standard error on the screen and what's produced on standard output in the file.

utility 2>&1 | tee output.log

Here, you redirect standard error to the same place as the standard output stream. This means that both streams will be piped to the tee utility as a single intermingled output stream, and that this standard output data will be saved to the given file by tee. The data would additionally be reproduced by tee in the console (this is what tee does, it duplicates data streams).

Which ever one of these is used depends on what you'd like to achieve.

Note that you would not be able to reproduce the effect of the second pipeline with just > (as in utility >output.log 2>&1, which would save both standard output and error in the file by first redirecting standard output to the output.log file and then redirecting standard error to where standard output is now going). You would need to use tee to get the data in the console as well as in the output file.


Additional notes:

The visible effect of the first command,

utility 2>&1 >output.log 

would be the same as

utility >output.log

I.e., the standard output goes to the file and standard error goes to the console.

If a further processing step was added to the end of each of the above commands, there would be a big difference though:

utility 2>&1 >output.log | more_stuff

utility >output.log      | more_stuff

In the first pipeline, more_stuff would get what's originally the standard error stream from utility as its standard input data, while in the second pipeline, since it's only the resulting standard output stream that is ever sent across a pipe, the more_stuff part of the pipeline would get nothing to read on its standard input.

8
  • With the command "utility 2>&1 | tee output.log, do you mean to say that since 1 is being directed to tee, 2 is as well. Since tee duplicates the stream, the output is both displayed on the console as well as written to file? Hence the difference between utility 2>&1 > output.log and utility 2>&1 | tee output.log is tee in that it duplicates the stream. Would that be correct?
    – Motivated
    Commented Jan 21, 2019 at 16:09
  • With the examples of utility 2>&1 > output.log | more_stuff and utility >ouput.log | more_stuff, is the difference that more_stuff` has the standard error output to the console as an input more_stuff? Since in the second example, there is no output to the the console, there is essentially no input to more_stuff? If yes, that isn't clear since the preceding paragraph you note that standard output goes to the file and standard error goes to the console.
    – Motivated
    Commented Jan 21, 2019 at 16:17
  • @Motivated Your first comment seems correct to me, yes. As for the second comment: In the first command, more_stuff would receive what utility originally sent to its error stream (but which was redirected to the standard output). Not because it would end up on the console if more_stuff wasn't there, but because it's going to the standard output stream. In the second command, more_stuff receives nothing as there is no standard output from the left hand side of the pipeline. The error stream from utility would still end up on the console in the 2nd command.
    – Kusalananda
    Commented Jan 21, 2019 at 18:31
  • Thanks. Do you mean that because the command utility > output.log | more_stuff does not result in an output in the standard output stream from a standard error point of view?
    – Motivated
    Commented Jan 22, 2019 at 5:48
  • @Motivated Since the left hand side doesn't produce anything on standard output (it's redirected), no data will be sent over the pipe.
    – Kusalananda
    Commented Jan 22, 2019 at 8:29
10

First command will do the another task:

After

2>&1 > output.log 

the old STDOUT will be saved (copied) in STDERR and then STDOUT will be redirected to file.

So, stdout will go to file and stderr will go to console.

And in

 2>&1 | tee output.log

both streams will be redirected to tee. Tee will duplicate any input to its stdout (the console in your case) and to file (output.log).

And there is another form of first:

    > output.log  2>&1

this will redirect both STDOUT and STDERR to the file.

4

The former outputs only to the file. The second outputs both to the file and to the screen.

4

The reason for 2>&1 | tee is to be able to capture both stdout and stderr to a log file and to see it on the screen at the same time. This could be done as >output.txt 2>&1 & tail -f as well, but you wouldn't know when the backgrounded command terminated - is the program terminated or is it running with no output. The 2>&1 | tee was a common idiom for programmers.

1
  • Do you mean to say that 2>&1 > file.txt for example would not capture both stdout and stderr to file.txt?
    – Motivated
    Commented Jan 21, 2019 at 7:28
0

Let's see some sample code first:

#include <stdio.h>
main() 
{
// message 1, on stdout (using  printf)
printf("%s",          "message 1, on stdout (using  printf)\n");

// message 2, on stdout (using fprintf)
fprintf(stdout, "%s", "message 2, on stdout (using fprintf)\n");

// message 3, on stderr (using fprintf)
fprintf(stderr, "%s", "message 3, on stderr (using fprintf)\n");
}

Lets compare the results:
./helloerror
+ file: no message; console: message 1,2,3;

./helloerror >error.txt
+ file: message 1,2; console: message 3;

./helloerror 2>&1 >error.txt
+ file: message 1,2; console: message 3;
+ same as ./helloerror >error.txt

./helloerror >error.txt 2>&1
+ file: message 3,1,2; console: no message;
+ note the order 3 is first, then 1, then 2

./helloerror | tee error.txt 2>&1
+ file: message 1,2; console: message 3,1,2;
+ note the order 3 is first, then 1, then 2

./helloerror 2>&1 | tee error.txt
+ file: message 3,1,2; console: message 3,1,2;

To use:
./helloerror >error.txt 2>&1
-> if one wants all(stdout+stderr) messages in file, but not pinted on console

./helloerror 2>&1 | tee error.txt
-> if one wants all(stdout+stderr) messages in file and printed on console

You must log in to answer this question.

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