【问题标题】:Redirect stderr to both file and stdout in C将标准错误重定向到 C 中的文件和标准输出
【发布时间】:2013-07-20 03:40:02
【问题描述】:

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

我尝试了以下方法:

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

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

可以不读取stderr的内容并将其复制到文件中吗?

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

【问题讨论】:

  • 您可以尝试“tail”在屏幕上查看您的输出文件。这是最简单的解决方案。
  • @OrcunC 我怎么知道有多少行尾??
  • 您不必知道行数。它总是显示最后 n 行。如果您正在寻找特定的模式,您可以轻松地将 tail 与 grep 结合使用,以获得强大的日志查看器。

标签: c logging posix stderr


【解决方案1】:

您必须“手动”复制数据以将其发送到两个地方,尽管使用特定于 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 源代码之间,您可能有大部分可供复制。

【讨论】:

【解决方案2】:

使用tee 命令的管道。

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

【讨论】:

  • 唯一的选择是将所有错误消息写入pFilestderr。没有内置方法可以同时写入两个目的地。
猜你喜欢
  • 2012-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-26
  • 1970-01-01
  • 1970-01-01
  • 2012-08-15
相关资源
最近更新 更多