4

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

我尝试了以下方法:

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

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

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

注意:我不想调用 shell (system, popen)。我确实查看了tee命令的执行情况coreutils。它将标准流复制到文件中。

4

2 回答 2

4

您必须“手动”复制数据以将其发送到两个地方,尽管使用特定于 linux 的 tee 和 splice 系统调用可以稍微提高效率(注意 tee syscall 不是 tee 命令,http://blog.superpat .com/2010/07/08/a-cup-of-tee-and-a-splice-of-cake/

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

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

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

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

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

无论如何,是的,它的代码比人们希望的要多,但是在 coreutils 和 gspawn.c 中的 tee 源代码之间,您可能可以复制大部分代码。

于 2013-07-21T23:39:58.303 回答
-1

tee对命令使用管道。

pFile = popen("tee logfile", "w");
dup2(fileno(pFile), STDERR_FILENO);
于 2013-07-20T04:02:49.390 回答