Reputation: 3275
I'm having some trouble using dup2
in trying to redirect both stdout
and stderr
into the same output file.
I'm using this explanatory code sample: (gcc 4.8.2, Ubuntu 14.04)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#define USE2FILES
int main()
{
int f1, f2, status;
f1 = open("test.out", O_CREAT | O_WRONLY, 0644);
if (f1 == -1) {
perror("open(): ");
}
status = dup2(f1, STDOUT_FILENO);
if (status == -1) {
perror("dup2(): ");
}
#ifdef USE2FILES
close(f1);
#endif
#ifdef USE2FILES
f2 = open("test.out", O_CREAT | O_WRONLY, 0644);
if (f2 == -1) {
perror("dup2(): ");
}
#else
f2 = f1;
#endif
status = dup2(f2, STDERR_FILENO);
if (status == -1) {
perror("dup2(): ");
}
close(f2);
fprintf(stderr, "test_stderr1\n");
fprintf(stdout, "test_stdout1\n");
fprintf(stderr, "test_stderr2\n");
fprintf(stdout, "test_stdout2\n");
fprintf(stderr, "test_stderr3\n");
fprintf(stdout, "test_stdout3\n");
fflush(stdout);
fflush(stderr);
return 0;
}
USE2FILES macro is supposed to switch between using either 2 file descriptors (to the same file) which get duped to stdout
and stderr
respectivly or 1 file descriptor which gets duplicated both to stdout
and stderr
.
I was under the impression that using 2 distinct file descriptors for redirection should work. However running this piece of code with USE2FILES on issues the following output in test.out
:
test_stdout1
test_stdout2
test_stdout3
If I then disable USE2FILES I get:
test_stderr1
test_stderr2
test_stderr3
test_stdout1
test_stdout2
test_stdout3
Seems like in the first case no output towards stderr
gets through. Is this behavior to be expected (am I missing something)?
EDIT: After accepted Chris Dodd's answer:
That's indeed a poor example. Changing the fprintf
sequence to something like this:
fprintf(stderr, "test_stderr+++++++++++++++++++++++++++++++++++++++++++++++++1\n");
fprintf(stdout, "test_stdout----------------------------------------1\n");
fprintf(stderr, "test_stderr++++++++++++++++++++++++++++++++++2\n");
fprintf(stdout, "test_stdout----------------2\n");
fprintf(stderr, "test_stderr++++++++++++++++++++++++++++3\n");
fprintf(stdout, "test_stdout----------------------3\n");
gets me this test.out
output:
test_stdout----------------------------------------1
test_stdout----------------2
test_stdout----------------------3
err++++++++++++++++++++++++++++3
showing pretty clearly stdout
& stderr
are competing with their writes over the same file.
Upvotes: 1
Views: 2468
Reputation: 126498
If you do two open
calls, you get two distinct kernel filehandles, each with its own I/O cursor (file offset), so writes to the two file descriptors will overwrite each other. If you use a single open
call, you only get a single filehandle that both file descriptors refer to, so each write (to each descriptor) will advance the output offset so the next write (with the other file descriptor) will write after it.
In your example, the strings written are the exact same length, so the write to stdout
exactly overwrites the preceeding write to stderr
. Note that the file write only occurs when the FILE
object is flushed, not (necessarily) when fprintf
is called.
You could also get the effect you seem to be trying to get by opening the files in O_APPEND
mode. This will cause every write to reposition the write offset to the current end of the file just before actually writing.
Upvotes: 5