给出以下答案(第一个c ++ 11答案):
How to execute a command and get output of command within C++ using POSIX?
以下是为方便起见的实施方案:
#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");
)并将stdout转换为字符串。
但它没有做的是获取命令返回码(通过/失败整数)或stderr。理想情况下,我想要一种方法来获取所有三个(返回代码,stdout,stderr)。
我会满足于stdout和stderr。我想我需要添加另一个管道,但是我无法真正看到第一个管道是如何设置来获得stdout所以我无法想象我将如何更改它以获得两者。
任何人都有任何想法如何做到这一点,或可能有效的替代方法?
更新
请参阅我的完整示例qazxsw poi输出:
here
您可以看到Start
1 res: /home
2 res: stdout
stderr
3 res:
End
不会像3 res:
那样打印stderr,但是stderr只是通过进程(而不是我的程序)在单独的行上转储到屏幕上。
外部自由人
我真的不想使用像Qt和boost这样的外部库 - 主要是因为我想要它的可移植性以及我工作的许多项目都不使用boost。但是我会标记包含这些选项的解决方案,因为它们对其他用户有效:)
完整解决方案使用评论/答案
感谢所有人的回答/评论,这里是修改后的解决方案(和runnable):
2 res: stdout
从working-solution的手册页:
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()的命令行重定向到stdout。这令人不安,两种流都是不可预测的混合。
如果你真的想要为stderr和stdout提供两个不同的文件描述符,一种方法是自己进行分叉并将新进程stdout / stderr复制到两个可从父进程访问的管道。 (见2>&1
和dup2()
)。我可以在这里详细介绍,但这是一种相当繁琐的做事方式,必须非常小心。互联网上充满了例子。
有一种可行的解决方法。您可以通过在cmd中附加“2>&1”将stderr重定向到stdout。这会满足你的需求吗?
您可以使用自定义删除器从管道获取返回代码:
pipe()