You tried using > but some (or all) of the output still appears on the screen.
For example, the compiler is producing some error messages.
1 2 3 4 5 6 7 |
$ gcc bad.c bad.c: In function `main': bad.c:3: error: `bad' undeclared (first use in this function) bad.c:3: error: (Each undeclared identifier is reported only once bad.c:3: error: for each function it appears in.) bad.c:3: error: parse error before "c" $ |
You wanted to capture those messages, so you tried redirecting the output:
1 2 3 4 5 6 7 |
$ gcc bad.c > save.it bad.c: In function `main': bad.c:3: error: `bad' undeclared (first use in this function) bad.c:3: error: (Each undeclared identifier is reported only once bad.c:3: error: for each function it appears in.) bad.c:3: error: parse error before "c" $ |
However, it doesn’t seem to have redirected anything. In fact, when you examine the file into which you were directing the output, that file is empty (zero bytes long):
1 2 3 4 |
$ ls -l save.it -rw-r--r-- 1 albing users 0 2005-11-13 15:30 save.it $ cat save.it $ |
Redirect the error output, as follows:
1 2 |
$ gcc bad.c 2> save.it $ |
The contents of save.it are now the error messages that we had seen before.
So what’s going on here? Every process in Unix and Linux typically starts out with three open file descriptors: one for input called standard input (STDIN), one for output called standard output (STDOUT), and one for error messages called standard error (STDERR).
It is really up to the programmer, who writes any particular program, to stick to these conventions and write error messages to standard error and to write the normally expected output to standard out, so there is no guarantee that
every error message that you ever get will go to standard error.
But most of the longestablished utilities are well behaved this way.
That is why these compiler messages are not being diverted with a simple > redirect; it only redirects standard output, not standard error.
Each file descriptor is indicated by a number, starting at 0. So standard input is 0, output is 1, and error is 2.
That means that you could redirect standard output with the slightly more verbose: 1> (rather than a simple >) followed by a filename, but there’s no need. The shorthand > is fine.
One other difference between standard output and standard error: standard output is buffered but standard error is unbuffered, that is every character is written individually, not collected together and written as a bunch.
This means that you see the error messages right away and that there is less chance of them being dropped when a fault occurs, but the cost is one of efficiency.
It’s not that standard output is unreliable, but in error situations (e.g., a program dies unexpectedly), the buffered output may not have made it to the screen before the program stops executing.
That’s why standard error is unbuffered: to be sure the message gets written. By contrast, standard out is buffered.
Only when the buffer is full (or when the file is closed) does the output actually get written.
It’s more efficient for the more frequently used output. Efficiency isn’t as important when an error is being reported.
What if you want to see the output as you are saving it? “Saving a Copy of Output Even While Using It As Input”
seems just the thing:
1 |
$ gcc bad.c 2>&1 | tee save.it |
This will take standard error and redirect it to standard out, piping them both into tee. The tee command will write its input to both the file (save.it) and tee’s standard out, which will go to your screen since it isn’t otherwise redirected.
This is a special case of redirecting because normally the order of the redirections is important. Compare these two commands:
1 2 3 |
$ somecmd >my.file 2>&1 $ somecmd 2>&1 >my.file |
In the first case, standard out is redirected to a file (my.file), and then standard error is redirected to the same place as standard out.
All output will appear in my.file. But that is not the case with the second command. In the second command, standard error is redirected to standard out (which at that point is connected to the screen), after which standard out is redirected to my.file.
Thus only standard out messages will be put in the file and errors will still show on the screen.
However, this ordering had to be subverted for pipes, since you couldn’t put the second redirect after the pipe symbol, because after the pipe comes the next command.
So bash makes an exception when you write:
1 |
$ somecmd 2>&1 | othercmd |
and recognizes that standard out is being piped. It therefore assumes that you want to include standard error in the piping when you write 2>&1 even though its normal ordering wouldn’t work that way.
The other result of this, and of pipe syntax in general, is that it gives us no way to pipe just standard error and not standard out into another command—unless we first swap the file descriptors (see the next recipe).