How to execute a command and get return code stdout and stderr of command in C++

怎甘沉沦 提交于 2019-11-30 09:58:30

From the man-page of popen:

The pclose() function waits for the associated process to terminate  and returns the exit status of the command as returned by wait4(2).

So, calling pclose() yourself (instead of using std::shared_ptr<>'s destructor-magic) will give you the return code of your process (or block if the process has not terminated).

std::string exec(const char* cmd) {
    std::array<char, 128> buffer;
    std::string result;

    auto pipe = popen(cmd, "r"); // get rid of shared_ptr

    if (!pipe) throw std::runtime_error("popen() failed!");

    while (!feof(pipe)) {
        if (fgets(buffer.data(), 128, pipe) != nullptr)
            result += buffer.data();
    }

    auto rc = pclose(pipe);

    if (rc == EXIT_SUCCESS) { // == 0

    } else if (rc == EXIT_FAILURE) {  // EXIT_FAILURE is not used by all programs, maybe needs some adaptation.

    }
    return result;
}

Getting stderr and stdout with popen(), I'm afraid you'd need to redirect the output of stderr to stdout from the command-line you're passing to popen() by adding 2>&1. This has the inconvinience that both streams are unpredictably mixed.

If you really want to have two distinguished file-descriptors for stderr and stdout, one way to do it is to do the forking yourself and to duplicate the new processes stdout/stderr to two pipes which are accessible from the parent process. (see dup2() and pipe()). I could go into more detail here, but this is quite a tedious way of doing things and much care must be taken. And the internet is full of examples.

There is kind of workaround possible. You may redirect the stderr to stdout by appending "2>&1" to your cmd. Would this suit your needs?

You can get the return code from the pipe by using a custom deleter as such:

#include <cstdio>
#include <iostream>
#include <memory>
#include <string>
#include <array>
#include <utility>

using namespace std;
pair<string, int> exec(const char* cmd) {
    array<char, 128> buffer;
    string result;
    int return_code = -1;
    auto pclose_wrapper = [&return_code](FILE* cmd){ return_code = pclose(cmd); };
    { // scope is important, have to make sure the ptr goes out of scope first
    const unique_ptr<FILE, decltype(pclose_wrapper)> pipe(popen(cmd, "r"), pclose_wrapper);
    if (pipe) {
        while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
            result += buffer.data();
        }
    }
    }
    return make_pair(result, return_code);
}

int main(int argc, char* argv[]) {
    if (argc <= 1) return 0;
    cout << "calling with " << argv[1] << '\n';
    const auto process_ret = exec(argv[1]);
    cout << "captured stdout : " << '\n' << process_ret.first << endl;
    cout << "program exited with status code " << process_ret.second << endl;
    return 0;
} 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!