如何在C中执行命令并获取命令的返回码stdout和stderr

新手上路,请多包涵

给出以下答案(第一个 c++11 答案):

如何使用 POSIX 在 C++ 中执行命令并获取命令的输出?

为了您的方便,这里是实现:

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

std::string exec(const char* cmd) {
    std::array<char, 128> buffer;
    std::string result;
    std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
    if (!pipe) throw std::runtime_error("popen() failed!");
    while (!feof(pipe.get())) {
        if (fgets(buffer.data(), 128, pipe.get()) != nullptr)
            result += buffer.data();
    }
    return result;
}

这非常适合执行命令(例如 std::string res = exec("ls"); )并将标准输出转换为字符串。

但它不做的是获取命令返回码(通过/失败整数)或标准错误。理想情况下,我想要一种方法来获取所有三个(返回代码、标准输出、标准错误)。

我会满足于标准输出和标准错误。我在想我需要添加另一个管道,但是我真的看不到第一个管道是如何设置来获取标准输出的,所以我想不出如何改变它来获取两者。

任何人有任何想法如何做到这一点,或者可能有效的替代方法?

更新

在这里 查看我的完整示例和输出:

 Start
1 res: /home

2 res: stdout

stderr
3 res:
End

您可以看到 3 res: 不会以与 2 res: stdout 相同的方式打印 stderr ,但 stderr 只是由进程(而不是我的程序)在单独的行上转储到屏幕上.

外部库

我真的不想使用像 Qt 和 boost 这样的外部库——主要是因为我想要它的可移植性,而且我从事的许多项目也不使用 boost。但是,我将标记包含这些选项的解决方案,因为它们对其他用户有效:)

使用评论/答案的完整解决方案

感谢大家的回答/评论,这是修改后的解决方案(并且可运行):

工作解决方案

原文由 code_fodder 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 778
1 个回答

popen 的手册页中:

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

因此,您自己调用 pclose() (而不是使用 std::shared_ptr<> 的析构函数)将为您提供进程的返回码(如果进程尚未终止,则阻止)。

 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;
}

使用 popen() 获取标准错误和标准输出,恐怕您需要通过添加 2>&1 从传递给 popen() 的命令行将标准错误的输出重定向到标准输出 --- 。这带来的不便之处在于两种流都不可预测地混合在一起。

如果您真的想为 stderr 和 stdout 提供两个不同的文件描述符,一种方法是自己进行分叉并将新进程 stdout/stderr 复制到两个可从父进程访问的管道。 (参见 dup2()pipe() )。我可以在这里更详细地介绍,但这是一种相当乏味的做事方式,必须非常小心。互联网上到处都是例子。

原文由 Patrick B. 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题