我在C中寻找一种以编程方式(即,不使用命令行重定向)实现'tee'功能的方式,以便我的stdout同时转到stdout和日志文件.这需要适用于我的代码和输出到stdout的所有链接库.有什么办法吗?
你可以popen()开球吧.
或者你可以通过像这样的子进程fork()管道stdout(改编自我写的真实的程序,所以它有效!):
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)\n",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('\n'==ch) {
                fflush(stdout);
                if(logFile)
                    fflush(logFile);
            }
        }
        putchar('\n');
        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]);  
    }
}
" popen()T恤"答案是正确的.这是一个示例程序,它正是这样做的:
#include "stdio.h"
#include "unistd.h"
int main (int argc, const char * argv[])
{
    printf("pre-tee\n");
    if(dup2(fileno(popen("tee out.txt", "w")), STDOUT_FILENO) < 0) {
        fprintf(stderr, "couldn't redirect output\n");
        return 1;
    }
    printf("post-tee\n");
    return 0;
}
说明:
popen()返回a FILE*,但dup2()需要一个文件描述符(fd),因此fileno()将其转换FILE*为fd.然后dup2(..., STDOUT_FILENO)说要用fd替换stdout popen().
意思是,您生成了一个子进程(popen),它将所有输入复制到stdout和一个文件,然后将stdout移植到该进程.