【发布时间】:2019-04-23 08:59:52
【问题描述】:
我可以使用 fork、execvp、pipe 等函数分别获取 stdout 和 stderr 并将它们放入两个单独的 C++ 字符串中。我如何使用这一系列函数将 stdout 和 stderr 组合成一个组合字符串,就像 shell 一样,就好像我像“2>&1”一样重定向?下面的示例仅捕获标准输出:
#include <sys/wait.h>
#include <unistd.h>
#include <string>
#include <vector>
std::string qx(const std::vector<std::string>& args) {
int stdout_fds[2];
pipe(stdout_fds);
int stderr_fds[2];
pipe(stderr_fds);
const pid_t pid = fork();
if (!pid) {
close(stdout_fds[0]);
dup2(stdout_fds[1], 1);
close(stdout_fds[1]);
close(stderr_fds[0]);
dup2(stderr_fds[1], 2);
close(stderr_fds[1]);
std::vector<char*> vc(args.size() + 1, NULL);
for (size_t i = 0; i < args.size(); ++i) {
vc[i] = const_cast<char*>(args[i].c_str());
}
execvp(vc[0], &vc[0]);
exit(0);
}
close(stdout_fds[1]);
std::string out;
const int buf_size = 4096;
char buffer[buf_size];
do {
const ssize_t r = read(stdout_fds[0], buffer, buf_size);
if (r > 0) {
out.append(buffer, r);
}
} while (errno == EAGAIN || errno == EINTR);
close(stdout_fds[0]);
close(stderr_fds[1]);
close(stderr_fds[0]);
int r, status;
do {
r = waitpid(pid, &status, 0);
} while (r == -1 && errno == EINTR);
return out;
}
int main() {
qx({"openssl", "hjas"});
qx({"openssl", "dkjsah"});
qx({"uname"});
qx({"uname"});
}
【问题讨论】:
-
感谢编辑
-
看起来你从来没有从标准错误管道中读取数据。如果你想组合 stdout+stderr,为什么不把一个管道复制到 1 和 2(stdout 和 stderr)?
-
if (!pid) {...}没有正确处理fork()失败的情况。
标签: c++ linux c++11 unix posix