如何将错误输出和标准输出重定向到同一个文件?

3

我有一个任务,需要将stderr和stdout都输出到一个名为“log.out”的文件中。我不允许删除代码行,只能添加它们。 stdout部分很容易,我只需添加close(1);就可以了。但是我已经花费了几个小时的时间学习如何使用整个dup/dup1/dup2技术,但即使在互联网上阅读了很多相关主题的内容,我仍然无法使它起作用。 如果有人能告诉我需要添加哪些代码行才能使其工作,并解释一下它的工作原理,那就太好了。 谢谢!

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>         // for fork, sleep etc.
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h> 
#include <fcntl.h>   

void fork_son(char*, int);
void do_son();
int open_file(char*);

int
main()
{
    fork_son("1st", 0);
    fork_son("2nd", 1);
    exit(0);
}

void fork_son(char* which, int need_file)
{
    int pid;
    int status;
    if (need_file)
    {
                close(1); //close stdout

        open_file("log.out");
    }
    // close and open files before forking

    pid = fork();
    if (pid <0) 
    {
        fprintf(stderr,"process %d, Fork Failed... Exiting\n", getpid());
        exit(1);
    }
    if (pid == 0)
        do_son(which);
    else
    {
        printf("waiting for %s son...", which);
        wait(&status);
        printf("%s son exited!\n", which);
    }
    return;
}   

void do_son(char* which) 
{
    fprintf(stdout,"Hello from %s son!\n", which);
    fprintf(stderr,"%s son: I'm going to exit\n", which);
    exit(0);
}   

int open_file(char* name)
{
    int fd;
    fd = open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    // check if open succeeded
    if (fd <0) 
    {
        fprintf(stderr, "ERROR: open \"%s\" failed (%d). Exiting\n", name, fd);
        exit(2);
    }
    // if (fd != 1) 
    // {
        // fprintf(stderr,"ERROR: open \"%s\" - fd is %d (expected 1). Exiting\n", name, fd);
        // exit(3);
    // }
    printf("opened file %s, file descriptor is: %d\n",name, fd);
    return(fd);
}


我们能看一下你如何尝试使用dup吗? - Daniel Walker
1
我想我刚刚解决了这个问题。 我已经添加到fork_son dup(1、2); 这是一个好的解决方案吗? - Dima
我认为你的意思是 dup2 - Daniel Walker
是的,我指的是dup2; - Dima
把它加到“fork_son”还是“open_file”更好? - Dima
1个回答

3
开放式的方式是搜索文件描述符表中的空闲项。其中,0、1和2分别保留给stdinstdoutstderr
stdin  - 0
stdout - 1
stderr - 2

如果你想将 stdoutstderr 重定向到 log.out,你可以简单地执行以下操作:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

int main()
{
    int fd = - 1;
    fd = open("log.out", O_RDWR | O_CREAT); 

    dup2(fd, 1); // redirects stdout to log.out
    dup2(fd, 2); // redirects stderr to log.out

    /* Print to stderr and to stdout */
    fprintf(stdout, "%s", "Hello world\n");     
    fprintf(stderr, "%s", "Stack overflow!\n");
    return 0;
}

如果您关心输出的顺序,那么在将标准输出重定向到文件时,应该在 fprintf 后调用 fflush 来刷新缓冲区,以免出现换行符不及时输出的情况。

输出到文件的顺序是否需要像"Hello world\n"然后是"Stack overflow!\n"这样的顺序而不需要刷新? - chux - Reinstate Monica
@chux-ReinstateMonica true,将stdout重定向到文件不会在换行符上刷新缓冲区,需要显式刷新。我会添加为注释。 - Tony

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接