启动应用程序,在C++中捕获标准输出和标准错误流

8

我该如何启动一个应用程序并通过stdout和stderr捕获输出?

我正在编写一个自动化构建系统,需要捕获输出以进行分析。我想更新svn仓库并获取版本号,以便在成功后将文件移动到autobuild/revNumber/。我还想使用make进行构建,并将编译文本上传到我的服务器,以便每个人都可以查看失败构建时的警告和错误。

我找不到system()函数,但在MSDN上找到了CreateProcess()函数。我能够启动我需要的程序,但我不知道如何捕获stderr和stdout。我注意到进程会单独启动,除非我设置断点并保持我的应用程序退出,否则它将保留所有文本在我的应用程序控制台窗口中。我还想等待所有进程完成,然后扫描它产生的数据以执行任何其他所需操作。我该怎么做?

3个回答

12

在真正的shell(指的是不是海贝壳 - 我的意思是不是C Shell或其衍生产品)中:


program arg1 arg2 >/tmp/log.file 2>&1

此命令以给定参数运行程序,并将标准输出重定向到 /tmp/log.file; 在结尾处 (象形文字) '2>&1' 的表示方式将标准错误(文件描述符 2)发送到与标准输出(文件描述符 1)相同的位置。请注意,操作顺序很重要;如果颠倒它们,那么标准错误将会去到标准输出的位置,然后标准输出(但不是标准错误)将会被重定向到文件。

所示的文件名选择由于许多原因都很糟糕 - 您应该允许用户选择目录,并且可能应在文件名中包含进程 ID 或时间戳。

LOG=${TMPDIR:-/tmp}/log.$$.$(date +%Y%m%d-%H%M%S)
program arg1 arg2 >$LOG 2>&1

在C++中,您可以使用从C继承而来的system()函数来运行进程。 如果您需要在C++程序中知道文件名(可能性很高),那么可以在程序中生成文件名(strftime()是您的好朋友),然后使用该文件名创建命令字符串。

严格地说,您还需要使用getenv()获取$TMPDIR和POSIX函数getpid()获取进程ID,然后可以模拟两行Shell脚本(尽管使用的PID将是C++程序的PID而不是启动的Shell的PID)。

您也可以使用POSIX popen()函数;您需要在创建的命令字符串中包含'2>&1'符号来将命令的标准错误发送到与标准输出相同的位置,但您不需要一个临时文件:

FILE *pp = popen("program arg1 arg2 2>&1", "r");

你可以接着读取文件流。我不确定是否有一种清晰的方法将C文件流映射到C ++ istream中,但可能存在。


我相信"&"字符/字形的名称是“和号”。 - J. Polfer
同意:但我指的是将“2>&1”全部视为“象形文字”(我会毫不犹豫地承认这是对该术语的误用)。 - Jonathan Leffler
我认为如果你把'2>&1'称为“重定向”,而不是“象形文字”,那会更清晰一些。对于不熟悉埃及语言学的人,如果去维基百科上查找这个术语,可能会变得非常困惑。 :) - J. Polfer

4

你需要填写STARTUP_INFO结构体,其中包括hStdInput、hStdOutput和hStdError。创建进程时记得继承句柄。

/* Assume you open a file handle or pipe called myoutput */
STARTUP_INFO si_startinfo;
ZeroMemory(&si_startinfo, sizeof(STARTUP_INFO));
si_startinfo.cb = sizeof(STARTUP_INFO);
si_startinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si_startinfo.hStdOutput = myoutput;
si_startinfo.hStdError = myoutput;
si_startifno.dwFlags != STARTF_USEHANDLES;

PROCESS_INFORMATION pi_procinfo;
ZeroMemory(&pi_procinfo, sizeof(PROCESS_INFORMATION);

CreateProcess(NULL, cmdline, NULL, NULL, true, 0, NULL, pathname, &si_startinfo, &pi_procinfo);

我没有展示错误处理方面,这是你需要做的。第五个参数设置为true以继承处理程序。其他人已经解释了如何创建管道,所以我不会在这里重复。


0

微软的CRT和MSDN库中包括了system函数和_popen函数。


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