在c ++中启动app,捕获stdout和stderr

时间:2008-11-19 00:36:50

标签: c++ process stdout capture launch

如何启动应用并通过stdout和stderr捕获输出?

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

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

3 个答案:

答案 0 :(得分:11)

在真正的炮弹中(意思是,不是海贝壳 - 我的意思是,不是在C壳牌或其衍生物中),那么:

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

这将使用给定的参数运行程序,并将stdout重定向到/tmp/log.file;最后的符号( hieroglyph )'2>&1'将stderr(文件描述符2)发送到stdout(文件描述符1)所在的相同位置。请注意,操作顺序很重要;如果你反转它们,那么标准错误将转到标准输出的位置,然后标准输出(但不是标准错误)将被重定向到文件。

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

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

在C ++中,您可以使用system()函数(继承自C)来运行进程。如果您需要知道C ++程序中的文件名(似是而非),那么在程序中生成名称(strftime()是您的朋友)并使用该文件名创建命令字符串。 (严格来说,您还需要getenv()来获取$ TMPDIR,并使用POSIX函数getpid()来获取进程ID,然后您可以模拟双线shell脚本(尽管使用的PID将是C ++程序,而不是已发布的shell。)

您可以使用POSIX popen()功能;您必须在您创建的命令字符串中包含“2>&1”表示法,以便将标准错误发送到与标准输出相同的位置,但您不需要临时文件:

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

然后您可以读取文件流。我不确定是否有一种将C文件流映射到C ++ istream的简洁方法;可能有。

答案 1 :(得分:4)

您需要填写STARTUP_INFO结构,该结构具有hStdInput,hStdOutput和hStdError。记住在CreateProcess时继承句柄。

/* 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);

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

答案 2 :(得分:0)

Microsoft的CRT和MSDN库确实包含系统函数和_popen函数。