c++ - 如何在 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:
不会以与打印相同的方式打印 stderr 2 res: stdout
,但 stderr 只是由进程(而不是我的程序)在单独的行上转储到屏幕上。
外部库
我真的不想使用像 Qt 和 boost 这样的外部库——主要是因为我想要它的可移植性,而且我从事的许多项目也不使用 boost。但是,我将标记包含这些选项的解决方案,因为它们对其他用户有效:)
使用评论/答案的完整解决方案
感谢大家的回答/评论,这是修改后的解决方案(并且可运行):
解决方案
从手册页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;
}
使用 获取 stderr 和 stdout popen()
,恐怕您需要通过添加将 stderr 的输出从传递给 popen() 的命令行重定向到2>&1
stdout 这带来的不便之处在于两种流都不可预测地混合在一起。
如果您真的想为 stderr 和 stdout 提供两个不同的文件描述符,一种方法是自己进行分叉并将新进程 stdout/stderr 复制到两个可从父进程访问的管道。(见dup2()
和pipe()
)。我可以在这里更详细地介绍,但这是一种相当乏味的做事方式,必须非常小心。互联网上到处都是例子。
推荐阅读
- content-management-system - DotCMS - 在模板设计器中添加同一容器的多个实例
- python - 如何通过 Openpyxl 从 xlsx 文件导入 Python 类?
- kubernetes - 如何在 kubernetes 上部署 2 个必须使用 yaml 链接在一起的 docker 容器?
- javascript - 在打开和关闭 Div 元素时添加动画
- java - 如何将异常从内部 doOnError 传播到外部 doOnError?
- extjs - 如何根据商店数据在一列中呈现不同的图标?
- node.js - 无法在使用 node-red 的项目中实现 webpack
- php - 如何在本机反应中通过 axios.get 获得数组而不是字符串的响应?
- python - 使用 super() 继承关键字参数,但在创建实例中指定之前不会列出它们
- random - 如何在 Agda 中生成随机数