cod*_*der 6 c++ stdout process stderr c++11
给出以下答案(第一个c ++ 11答案):
以下是您的实施方便:
#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;
}
Run Code Online (Sandbox Code Playgroud)
这非常适合执行命令(例如std::string res = exec("ls");)并将stdout转换为字符串.
但它没有做的是获取命令返回码(通过/失败整数)或stderr.理想情况下,我想要一种方法来获取所有三个(返回代码,stdout,stderr).
我会满足于stdout和stderr.我想我需要添加另一个管道,但是我无法真正看到第一个管道是如何设置来获得stdout所以我无法想象我将如何更改它以获得两者.
任何人都有任何想法如何做到这一点,或可能有效的替代方法?
更新
看到我的完整的例子这里 witht输出:
Start
1 res: /home
2 res: stdout
stderr
3 res:
End
Run Code Online (Sandbox Code Playgroud)
您可以看到它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).
Run Code Online (Sandbox Code Playgroud)
因此,调用pclose()自己(而不是使用std::shared_ptr<>'s析构函数 - 魔法)将为您提供进程的返回代码(如果进程尚未终止,则为块).
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;
}
Run Code Online (Sandbox Code Playgroud)
得到stderr和stdout popen(),我担心你需要通过添加将stderr的输出从你传递给popen()的命令行重定向到stdout 2>&1.这令人不安,两种流都是不可预测的混合.
如果你真的想要为stderr和stdout提供两个不同的文件描述符,一种方法是自己进行分叉并将新进程stdout/stderr复制到两个可从父进程访问的管道.(见dup2()和pipe()).我可以在这里详细介绍,但这是一种非常繁琐的做事方式,必须非常小心.互联网上充满了例子.
下面是帕特里克的一个略有不同的版本。B答案,使用fread()而不是fgets().
fread()建议使用Antti Haapala在这个帖子中
如何使用 POSIX 在 C++ 中执行命令并获取命令的输出?
此版本将标准输出读取到std::string,它必须作为第二个参数传递。
该函数返回 执行的退出代码cmd,如从pclose()。
要获得也,请添加到:stderr的末尾,按照Alex 的建议cmd"2>&1"在同一个线程中所建议的那样。
main()下面的函数展示了如何使用:
int execute(std::string cmd, std::string& output)
Run Code Online (Sandbox Code Playgroud)
列出当前目录并将其打印到标准输出:
#include <iostream>
#include <array>
#include <unistd.h>
int execute(std::string cmd, std::string& output) {
const int bufsize=128;
std::array<char, bufsize> buffer;
auto pipe = popen(cmd.c_str(), "r");
if (!pipe) throw std::runtime_error("popen() failed!");
size_t count;
do {
if ((count = fread(buffer.data(), 1, bufsize, pipe)) > 0) {
output.insert(output.end(), std::begin(buffer), std::next(std::begin(buffer), count));
}
} while(count > 0);
return pclose(pipe);
}
int main(int argc, char** argv) {
std::string output;
execute("ls", output);
std::cout << output;
}
Run Code Online (Sandbox Code Playgroud)
小智 5
您可以使用自定义删除器从管道获取返回代码,如下所示:
#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;
}
Run Code Online (Sandbox Code Playgroud)