English 中文(简体)
How can I implement tee programmatically in C?
原标题:
  • 时间:2009-11-19 09:20:30
  •  标签:
  • c
  • stdout
  • tee

I m looking for a way in C to programmatically (ie, not using redirection from the command line) implement tee functionality such that my stdout goes to both stdout and a log file. This needs to work for both my code and all linked libraries that output to stdout. Any way to do this?

问题回答

You could popen() the tee program.

Or you can fork() and pipe stdout through a child process such as this (adapted from a real live program I wrote, so it works!):

void tee(const char* fname) {
    int pipe_fd[2];
    check(pipe(pipe_fd));
    const pid_t pid = fork();
    check(pid);
    if(!pid) { // our log child
        close(pipe_fd[1]); // Close unused write end
        FILE* logFile = fname? fopen(fname,"a"): NULL;
        if(fname && !logFile)
            fprintf(stderr,"cannot open log file "%s": %d (%s)
",fname,errno,strerror(errno));
        char ch;
        while(read(pipe_fd[0],&ch,1) > 0) {
            //### any timestamp logic or whatever here
            putchar(ch);
            if(logFile)
                fputc(ch,logFile);
            if( 
 ==ch) {
                fflush(stdout);
                if(logFile)
                    fflush(logFile);
            }
        }
        putchar( 
 );
        close(pipe_fd[0]);
        if(logFile)
            fclose(logFile);
        exit(EXIT_SUCCESS);
    } else {
        close(pipe_fd[0]); // Close unused read end
        // redirect stdout and stderr
        dup2(pipe_fd[1],STDOUT_FILENO);  
        dup2(pipe_fd[1],STDERR_FILENO);  
        close(pipe_fd[1]);  
    }
}

The "popen() tee" answers were correct. Here is an example program that does exactly that:

#include "stdio.h"
#include "unistd.h"

int main (int argc, const char * argv[])
{
    printf("pre-tee
");

    if(dup2(fileno(popen("tee out.txt", "w")), STDOUT_FILENO) < 0) {
        fprintf(stderr, "couldn t redirect output
");
        return 1;
    }

    printf("post-tee
");

    return 0;
}

Explanation:

popen() returns a FILE*, but dup2() expects a file descriptor (fd), so fileno() converts the FILE* to an fd. Then dup2(..., STDOUT_FILENO) says to replace stdout with the fd from popen().

Meaning, you spawn a child process (popen) that copies all its input to stdout and a file, then you port your stdout to that process.

You could use pipe(2) and dup2(2) to connect your standard out to a file descriptor you can read from. Then you can have a separate thread monitoring that file descriptor, writing everything it gets to a log file and the original stdout (saved avay to another filedescriptor by dup2 before connecting the pipe). But you would need a background thread.

Actually, I think the popen tee method suggested by vatine is probably simpler and safer (as long as you don t need to do anyhing extra with the log file, such as timestamping or encoding or something).

You can use forkpty() with exec() to execute the monitored program with its parameters. forkpty() returns a file descriptor which is redirected to the programs stdin and stdout. Whatever is written to the file descriptor is the input of the program. Whatever is written by the program can be read from the file descriptor.

The second part is to read in a loop the program s output and write it to a file and also print it to stdout.

Example:

pid = forkpty(&fd, NULL, NULL, NULL);
if (pid<0)
    return -1;

if (!pid) /* Child */
{
execl("/bin/ping", "/bin/ping", "-c", "1", "-W", "1", "192.168.3.19", NULL);
}

/* Parent */
waitpid(pid, &status, 0);
return WEXITSTATUS(status);

There s no trivial way of doing this in C. I suspect the easiest would be to call popen(3), with tee as the command and the desired log file as an arument, then dup2(2) the file descriptor of the newly-opened FILE* onto fd 1.

But that looks kinda ugly and I must say that I have NOT tried this.





相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...

热门标签