我可以使用fork,execvp,pipe等函数分别获取stdout和stderr并将它们放入两个单独的C ++字符串中。我如何使用这一系列函数将stdout和stderr都组合成一个单独的组合字符串(如shell),就像我要像“ 2>&1”一样进行重定向?下面的示例仅捕获stdout:
#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"});
}
答案 0 :(得分:3)
只需使用一个管道收集两个管道:
std::string qx(const std::vector<std::string>& args) {
int output[2];
pipe(output);
const pid_t pid = fork();
if (!pid) {
// collect both stdout and stderr to the one pipe
close(output[0]);
dup2(output[1], STDOUT_FILENO);
dup2(output[1], STDERR_FILENO);
close(output[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]);
// if execvp() fails, we do *not* want to call exit()
// since that can call exit handlers and flush buffers
// copied from the parent process
_exit(0);
}
close(output[1]);
std::string out;
const int buf_size = 4096;
char buffer[buf_size];
do {
errno = 0;
const ssize_t r = read(output[0], buffer, buf_size);
if (r > 0) {
out.append(buffer, r);
}
} while (errno == EAGAIN || errno == EINTR);
请注意,您的原始代码不会收集孩子的stderr
输出。如果子进程向stderr
写入足够多的内容以使管道填满,则子进程可能会阻塞。