将stderr重定向到C中的文件和stdout

时间:2013-07-20 03:40:03

标签: c logging posix stderr

有没有办法将错误信息写入日志文件并在终端屏幕上打印?

我尝试了以下内容:

dup2(fileno(pFile), STDERR_FILENO); /* redirect stderr to file */

stderr 重定向到该文件。但是,它会将错误消息写入文件,但不会在屏幕上显示。

这可以在不读取并将stderr的内容复制到文件的情况下完成吗?

注意:我想不调用shell(系统,popen)。我确实查看了tee coreutils命令的实现。它将标准流复制到文件。

2 个答案:

答案 0 :(得分:4)

你必须“手动”复制数据以将其发送到两个地方,尽管使用特定于Linux的tee和splice系统调用可以稍微提高效率(注意tee syscall not tee command,{{3} })

听起来你可能知道怎么做而且只是希望不要,但对于其他人来说,解决方案可能是这样的:

将原始stderr(通常是终端)复制到新的文件描述符以保存它。然后用管道()制作一个管道。 dup2将管道的写入结束到fd 2.关闭原始写入结束fd。现在你的stderr是一个管道。启动一个线程或进程。在此线程中,您将数据从管道的读取端复制到文件和保存的原始stderr中。当线程或进程获取EOF读取管道时,关闭它并退出。

popen(“tee”)解决方案是相同的,除了它创建一个额外的shell进程(并且你必须正确引用传递给shell的文件名,以防它中有特殊字符...一定要测试奇怪的文件名,其中包含大于号,空格和引号...)。如果使用popen我认为你也可能有一个(化妆品?)问题你不能pclose(),因为你的stderr会停止工作,所以你总是会留下额外的fd打开而不会wait4()孩子。 / p>

如果你使用像GLib这样的东西,它有一个g_spawn_async函数系列,可用于在没有shell的情况下生成tee命令。否则,您必须手动执行fork / exec操作以避免shell;你可以执行tee命令,或者你可以fork而不是exec - 只需在fork执行stderr复制之后使用子代码,不要依赖于tee命令。或者,您可以使用线程而不是进程。

如果使用fork,你可能会发现gspawn.c中的源代码很有用;在任何复杂的程序中,FD_CLOEXEC并不是unix上的默认设置,这很容易让孩子继承导致问题的描述符。 避免僵尸进程并处理所有错误并等等等等也是非常烦人的。

无论如何,这是代码比人们希望的更多,但是在coreutils和gspawn.c中的tee源之间你可能有大部分可用于复制。

答案 1 :(得分:-1)

使用管道tee命令。

pFile = popen("tee logfile", "w");
dup2(fileno(pFile), STDERR_FILENO);