How to write to stderr so people will like you
Suppose that you're writing a command like, say, make
; it writes
progress output to standard output and error reports to standard error,
and it doesn't necessarily immediately terminate when it encounters an
error (or prints a warning; the important thing is that it keeps running
after it prints things to standard error).
There's a subtle catch in how you want to print things (such as standard error messages) to stderr in such a program. You don't want to just do the straightforward thing of printing to stderr and being done with it. Instead, you want to print messages to stderr with the following sequence: flush stdout, write your message to stderr, then flush stderr.
(This is obviously inapplicable if all of your IO is complete unbuffered and there is nothing to flush. But this is an uncommon case.)
To convince you of this, here's a little test program to illustrate what goes wrong if you don't:
$ cat tst.c #include <stdio.h> int main(int argc, char **argv) { printf("line 1\n"); fprintf(stderr, "stderr line 1\n"); printf("line 2\n"); fprintf(stderr, "stderr line 2\n"); }
And now let's show what goes wrong:
$ ./tst >/tmp/logit 2>&1; cat /tmp/logit stderr line 1 stderr line 2 line 1 line 2
(Note that these results are system and language dependent; your choices may behave differently.)
That's not exactly the output that you'd expect or that you want, seeing as the error messages have completely been relocated out of their actual context.
In most implementations of buffered IO, interactive IO is line buffered
(it is written out to you after every newline) while IO to anything else
is block buffered, generally in reasonable size blocks. The problem is
that when you redirect the output of this program into a file, stdout is
buffered separately from stderr even though they have been redirected
to the same place. As a result, at the end of tst
you get all of the
stdout messages flushed out in one block, not interleaved with the
stderr messages.
(Note that on some systems and in some languages stderr is always line buffered or unbuffered, even when it is being written to files.)
Doing the flush dance defeats this separate buffering and so makes stdout and stderr be properly interleaved even when redirected into a file. Note that it may not sufficient to just flush stdout before writing to stderr, because if stderr is block buffered there's nothing that prevents subsequent messages to stdout being flushed out before the stderr message.
(Note that programs that run other programs need to do more than just this; they need to flush stdout and perhaps stderr before they start another program.)
Comments on this page:
|
|