在C语言中将stderr重定向到文件和标准输出流

4
有没有一种方法将错误消息写入日志文件并在终端屏幕上打印出来?
我尝试了以下方法:
dup2(fileno(pFile), STDERR_FILENO); /* redirect stderr to file */

stderr重定向到文件中是可能的。然而,这只会将错误消息写入文件中,而不在屏幕上显示。

是否可以在不读取并复制stderr内容到文件的情况下完成此操作?

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


你可以尝试使用"tail"命令在屏幕上查看输出文件。这是最简单的解决方案。 - O.C.
@OrcunC 我怎么知道要跟踪多少行? - PALEN
你不需要知道行数,它总是显示最后的n行。如果你正在寻找特定的模式,你也可以轻松地将tail与grep结合使用,以获得强大的日志查看器。 - O.C.
2个回答

4
您需要手动复制数据并将其发送到两个位置,但是使用Linux特定的tee和splice系统调用可以使其稍微更有效(请注意,这里指的是tee系统调用而不是tee命令,详见http://blog.superpat.com/2010/07/08/a-cup-of-tee-and-a-splice-of-cake/)。
听起来您可能已经知道如何做了,只是希望避免这样做,但对于其他人来说,解决方案可能是这样的:
将原始stderr(通常是终端)复制到一个新的文件描述符中以保存它。然后使用pipe()创建一个管道。将管道的写端复制到fd 2。关闭原始写入端fd。现在您的stderr是一个管道。启动一个线程或进程。在此线程中,将数据从管道的读取端复制到文件和您保存的原始stderr。当线程或进程在读取管道时得到EOF时,关闭它并退出。 popen("tee")解决方案与上述相同,只是它创建了一个额外的shell进程(并且您必须正确引用传递给shell的文件名,以防其中有特殊字符...一定要测试具有大于号、空格和引号的奇怪文件名...)。如果使用popen,我认为您可能会遇到(美学上的?)问题,即无法pclose(),因为您的stderr将停止工作,因此您将始终保留一个额外的fd打开,并且不会等待子进程。
如果您正在使用类似GLib的东西,则可以使用g_spawn_async系列函数来生成tee命令而不使用shell。否则,您必须手动执行fork/exec操作以避免使用shell;您可以执行tee命令,或者您可以fork但不执行-只需在fork之后的子代码中完成stderr复制,不要依赖tee命令。或者,您可以使用线程而不是进程。
如果使用fork,则可能会发现gspawn.c中的源代码非常有用;在任何复杂程序中,FD_CLOEXEC在Unix上不是默认值,例如,很容易继承导致问题的描述符的子级。还很烦人地避免僵尸进程并处理所有错误等等。
总之,这需要比人们希望的更多的代码,但在coreutils和gspawn.c中,您可能已经有了大部分可用于复制的代码。

非常感谢。此外,这篇文章很相似:https://dev59.com/TVDTa4cB1Zd3GeqPIFBh。然而,在这种情况下,您的答案是我需要的解决方案。 - PALEN

-1
使用管道符号来使用tee命令。
pFile = popen("tee logfile", "w");
dup2(fileno(pFile), STDERR_FILENO);

3
唯一的选择是将所有错误消息写入pFilestderr。没有内置的方法可以同时写入两个目标地点。 - Barmar

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