【问题标题】:How to capture the exit_code and stderr of the command that is run in C++?如何捕获在 C++ 中运行的命令的 exit_code 和 stderr?
【发布时间】:2013-02-10 02:51:15
【问题描述】:

我正在编写一个 c++ 程序,它执行和输出(实时)一个 shell 脚本、makefile 或只是另一个程序。但是,当有错误或没有错误时,我希望我的程序以不同的方式返回。

#include "execxi.h"



using namespace std;


int execXI::run(string command)
{

    FILE *in;
    char buff[512];
    // is this the check for command execution exited with not 0?
    if(!(in = popen(command.c_str(), "r"))){
            // I want to return the exit code and error message too if any
        return 1;
    }
    // this part echoes the output of the command that's executed
    while(fgets(buff, sizeof(buff), in)!=NULL){
        cout << buff;
    }
    pclose(in);
    return 0;



}

是我目前所拥有的。

假设这个脚本运行 make 来构建一个程序,它给出了一个这样的错误

on_target_webkit_version out/Release/obj/gen/webkit_version.h
Traceback (most recent call last):
  File "../build/webkit_version.py", line 107, in <module>
    sys.exit(main())
  File "../build/webkit_version.py", line 103, in main
    return EmitVersionHeader(*sys.argv[1:])
  File "../build/webkit_version.py", line 86, in EmitVersionHeader
    webkit_revision = GetWebKitRevision(webkit_dir, version_file)
  File "../build/webkit_version.py", line 60, in GetWebKitRevision
    version_info = lastchange.FetchVersionInfo(
AttributeError: 'module' object has no attribute 'FetchVersionInfo'
make: *** [out/Release/obj/gen/webkit_version.h] Error 1
  • 我是否有可能知道这退出时出错?

    • 因为这是一个错误,它会以代码else than 0 退出吗?

    • 最后一部分是在stderr中输出的吗?

考虑到make 退出的代码不是0,比如说1,它在stderr 中输出,我最终无法捕获这些退出代码和错误消息吗?

如何在程序输出结果后捕获退出码和stderr,并在函数中返回exit code/stderr

【问题讨论】:

标签: c++ popen stderr exit-code


【解决方案1】:

如果您对错误代码感兴趣,这是一种更便携的获取方式,而不是除以 256:

printf("Exit code: %i\n", WEXITSTATUS(pclose(fp)));

但是,popen 是一种方法,因此您要么通过 shell 中通常的重定向样式创建进一步的解决方法,要么按照这个未经测试的代码来做正确的事:

#include <unistd.h>
#include <stdio.h>

/* since pipes are unidirectional, we need two pipes.
   one for data to flow from parent's stdout to child's
   stdin and the other for child's stdout to flow to
   parent's stdin */

#define NUM_PIPES          2

#define PARENT_WRITE_PIPE  0
#define PARENT_READ_PIPE   1

int pipes[NUM_PIPES][2];

/* always in a pipe[], pipe[0] is for read and 
   pipe[1] is for write */
#define READ_FD  0
#define WRITE_FD 1

#define PARENT_READ_FD  ( pipes[PARENT_READ_PIPE][READ_FD]   )
#define PARENT_WRITE_FD ( pipes[PARENT_WRITE_PIPE][WRITE_FD] )

#define CHILD_READ_FD   ( pipes[PARENT_WRITE_PIPE][READ_FD]  )
#define CHILD_WRITE_FD  ( pipes[PARENT_READ_PIPE][WRITE_FD]  )

void
main()
{
    int outfd[2];
    int infd[2];

    // pipes for parent to write and read
    pipe(pipes[PARENT_READ_PIPE]);
    pipe(pipes[PARENT_WRITE_PIPE]);

    if(!fork()) {
        char *argv[]={ "/usr/bin/bc", "-q", 0};

        dup2(CHILD_READ_FD, STDIN_FILENO);
        dup2(CHILD_WRITE_FD, STDOUT_FILENO);

        /* Close fds not required by child. Also, we don't
           want the exec'ed program to know these existed */
        close(CHILD_READ_FD);
        close(CHILD_WRITE_FD);
        close(PARENT_READ_FD);
        close(PARENT_WRITE_FD);

        execv(argv[0], argv);
    } else {
        char buffer[100];
        int count;

        /* close fds not required by parent */       
        close(CHILD_READ_FD);
        close(CHILD_WRITE_FD);

        // Write to child’s stdin
        write(PARENT_WRITE_FD, "2^32\n", 5);

        // Read from child’s stdout
        count = read(PARENT_READ_FD, buffer, sizeof(buffer)-1);
        if (count >= 0) {
            buffer[count] = 0;
            printf("%s", buffer);
        } else {
            printf("IO Error\n");
        }
    }
}

代码来自这里:

http://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/

【讨论】:

  • 对我来说,使用WEXITSTATUSpclose() 将返回1 表示成功,-1 表示不成功。这听起来是对的,还是我做错了什么?
  • 有一个解释groups.google.com/forum/#!topic/utah-c/g4MpZVnJ7es关于不同的非0退出代码
  • 仅当WIFEXITED 返回真时才使用WEXITSTATUS。这适用于程序未正常终止的情况。 int st = pclose(fp); if(WIFEXITED(st)) printf("Exit code: %i\n", WEXITSTATUS(st));
【解决方案2】:

子进程的返回值在前16 8位。你有 将 pclose 的返回值除以 256,然后得到 搜索到子进程的返回值。

来自http://bytes.com/topic/c/answers/131694-pclose-returning-termination-status-command

我的回答是pclose(in)/256 是退出代码。

我仍然不知道如何以不同的方式捕获 stderr 或 sdtout,但在有答案之前,我会接受这个作为我的答案。

【讨论】:

  • 这里有同样的问题。您是否找到了未解决问题的解决方案?我的解决方法是将 stderr 通过管道传输到一个文件中,然后通过 popen 调用再次读取该文件。
  • @Strubl Kind of... 看看这个github.com/aponxi/npm-execxi/blob/master/execxi.cpp 我已经为nodejs 编写了一个C++ 扩展来执行shell 命令。我想我还没有实现划分标准错误和标准输出,因为并非所有程序都使用标准错误来解决我的错误。而且我相信我想出了一些方法来阻止file write than read 的方法。我希望阅读我在该代码中所做的事情会有所帮助(已经有一段时间了,所以我对细节很模糊。)
  • 你也可以使用shell重定向,2>&1,搜索错误信息。
  • @Logan:我根据我的知识和上面的评论提交了一个答案。
  • 最好使用WEXITSTATUS(pclose(xxx))而不是除以256。另外,如果除以256得到正确答案,则退出代码在前8位,而不是前16位作为答案最初声明。
【解决方案3】:

感谢关于退出代码 Logan 的回复。

我相信获取 stderr 的往返过程是将其重定向到一个临时文件:

FILE* f = popen("cmd 2>/tmp/tmpfile.txt", "r");

【讨论】:

  • 创建一个唯一的输出文件(可能使用 pid),这样当你需要运行 2+ 个副本时,你会得到有用的输出。
  • 使用 tempnamtmpfiletmpnam 创建临时文件,从不硬编码名称。
  • 我相信将 stederr 重定向到 stdout 对 popen 有效:popen("command 2>&1", "r");
猜你喜欢
  • 1970-01-01
  • 2021-05-29
  • 2012-08-22
  • 2023-04-05
  • 1970-01-01
  • 2018-05-04
  • 2022-01-18
  • 1970-01-01
相关资源
最近更新 更多