如何在C++中执行命令并获取命令的返回码stdout和stderr
给出以下答案(第一个 c++11 答案):
Given the following answer (first c++11 answer):
如何在 C++ 中使用 POSIX 执行命令并获取命令的输出?
为了您的方便,以下是实现:
Here is the implementation for your convenience:
#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");
)并将标准输出转换为字符串非常有效.
This works really nicely to execute a command (e.g. std::string res = exec("ls");
) and get the stdout into a string.
但它不做的是获取命令返回码(通过/失败整数)或标准错误.理想情况下,我想要一种方法来获得所有三个(返回码、标准输出、标准错误).
But what it does not do is get the command return code (pass/fail integer) or the stderr. Ideally I would like a way to get all three (return code, stdout, stderr).
我会接受标准输出和标准错误.我想我需要添加另一个管道,但我真的看不到第一个管道是如何设置以获得标准输出的,所以我无法考虑如何更改它以获得两个.
I would settle for stdout and stderr. I am thinking that I need to add another pipe, but I can't really see how the first pipe is setup to get stdout so I can't think how I would change it to get both.
有人知道如何做到这一点,或者有其他可行的方法吗?
Any one got any ideas how to do that, or alternative approaches that may work?
更新
查看我的完整示例 此处 输出:
See my complete example here with the output:
Start
1 res: /home
2 res: stdout
stderr
3 res:
End
您可以看到 3 res:
不像 2 res: stdout
那样打印 stderr,但 stderr 只是在单独的屏幕上转储到屏幕上逐个流程(而不是我的程序).
You can see that 3 res:
does not print stderr in the same way that 2 res: stdout
does, but stderr is just dumped onto the screen on a separate line by the process (and not my program).
外部库
我真的不想使用像 Qt 和 boost 这样的外部库――主要是因为我想要它的可移植性,而且我从事的许多项目都不使用 boost.但是我会标记包含这些选项的解决方案,因为它们对其他用户有效:)
I really don't want to use external libraries like Qt and boost - mostly because I want the portability of it and also many projects that I work on don't use boost. However I will mark up solutions that contain these options as they are valid for other users :)
使用评论/答案的完整解决方案
感谢大家的回答/评论,这是修改后的解决方案(并且可以运行):
Thanks all for your answers / comments, here is the modified solution (and runable):
工作解决方案
推荐答案
来自 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<>
的析构函数魔术)将为您提供进程的返回码(如果进程未终止,则阻塞).
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;
}
使用 popen()
获取 stderr 和 stdout,恐怕您需要通过添加将 stderr 的输出从传递给 popen() 的命令行重定向到 stdout2>&1
.这带来了两个流不可预测地混合的不便.
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.
如果您真的想要为 stderr 和 stdout 拥有两个不同的文件描述符,一种方法是自己进行分叉并将新进程 stdout/stderr 复制到可从父进程访问的两个管道中.(参见 dup2()
和 pipe()
).我可以在这里详细介绍,但这是一种相当乏味的做事方式,必须非常小心.互联网上到处都是例子.
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.
相关文章