代码之家  ›  专栏  ›  技术社区  ›  ericcurtin

如何将STDRR和STDUT结合到单个C++字符串中?

  •  0
  • ericcurtin  · 技术社区  · 6 年前

    我可以用叉子、ExvVP、管道等函数分别抓取STDUT和STDRR,并将它们放入两个独立的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"});
    }
    
    1 回复  |  直到 6 年前
        1
  •  3
  •   Andrew Henle    6 年前

    只需使用一根管道收集两个:

    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 输出。孩子写得够吗 标准错误 如果管道填满,子进程可能会阻塞。