【问题标题】:Is it possible to redirect child process's stdout to another file in parent process?是否可以将子进程的标准输出重定向到父进程中的另一个文件?
【发布时间】:2019-02-04 21:44:51
【问题描述】:

子进程运行一个由 Qualcomm 提供的 bin 文件。 子进程由我开发的父进程调用。 当子进程运行时,它总是在 shell 命令中打印大量日志。 那么,我是否能够将 Qualcomm 的 outstream 从 stdout 重定向到父进程中的另一个文件? 如你所知,推动高通更新这个bin文件几乎是不可能的。 非常感谢~

【问题讨论】:

  • 这真的是一个合适的副本吗?我认为这个问题是关于将孩子的输出发送到实际文件,而不是在父母的记忆中处理它。
  • stackoverflow.com/a/40667558/2193968 怎么样(用其他文件替换 /dev/null)
  • @JerryJeremiah 谢谢。但是在演示代码中,重定向涉及到子进程...
  • @aschepler 是的,将子进程的输出重定向到实际文件。但是子进程中运行的bin文件是不能修改的,那么父进程是否可以控制子进程的重定向呢?
  • 像 system(“./qualcommbinary > out.txt”) 这样的东西就够了吗?

标签: c++ linux


【解决方案1】:

对于 POSIX,这是可能的,因为 POSIX shell 会这样做。对于 POSIX,执行程序有两个步骤。首先使用fork克隆父进程创建子进程。然后让子进程使用 exec 系列系统调用之一来执行所选程序而不是父程序。在这两个步骤之间,为子进程执行的代码可以执行额外的操作,这将影响要执行的程序的环境。特别是,代码可以打开要重定向到的文件的文件描述符,关闭 stdout 文件描述符,然后将文件的文件描述符复制到用于 stdout 的值 (1)。

【讨论】:

    【解决方案2】:

    您可以创建自己的管道并将它们附加到子进程。

    1. 创建 3 个管道。他们将替换孩子的标准输入、标准输出、标准错误。
    2. fork()
    3. 在子进程close() 管道的父端。关闭标准输入、标准输出和标准错误。
    4. 父进程close()管道的子端。
    5. dup2() 管道结束于子进程,旨在作为新的标准输入,输出,错误
    6. exec()孩子。

    现在您将所有输出从子级传递到父级管道。当然,您需要从来自孩子的管道中读取,否则它将阻止对 stdout/stderr 的任何写入。为此,您可以使用select()poll()epoll() 多路复用算法。

    https://linux.die.net/man/2/pipe

    https://linux.die.net/man/2/dup2

    https://linux.die.net/man/2/execve

    https://linux.die.net/man/2/fork

    【讨论】:

      【解决方案3】:

      这里的关键部分是 POSIX 函数dup2,它可以让您从本质上将一个文件描述符替换为另一个文件描述符。如果您使用fork(而不是system),您实际上可以控制在forkexec* 之间加载另一个可执行文件的子进程中发生的事情。

      #include <cstdlib>
      extern "C" {
      #include <fcntl.h>
      #include <unistd.h>
      }
      #include <stdexcept>
      #include <iostream>
      
      pid_t start_child(const char* program, const char* output_filename)
      {
          pid_t pid = fork();
          if (pid < 0) {
              // fork failed!
              std::perror("fork");
              throw std::runtime_error("fork failed");
          } else if (pid == 0) {
              // This code runs in the child process.
              int output_fd = open(output_filename, O_WRONLY | O_CREAT | O_TRUNC);
              if (output_fd < 0) {
                  std::cerr << "Failed to open log file " << output_filename << ":"
                            << std::endl;
                  std::perror("open");
                  std::exit(1);
              }
              // Replace the child's stdout and stderr handles with the log file handle:
              if (dup2(output_fd, STDOUT_FILENO) < 0) {
                  std::perror("dup2 (stdout)");
                  std::exit(1);
              }
              if (dup2(output_fd, STDERR_FILENO) < 0) {
                  std::perror("dup2 (stderr)");
                  std::exit(1);
              }
              if (execl(program, program, (char*)nullptr) < 0) {
                  // These messages will actually go into the file.
                  std::cerr << "Failed to exec program " << program << ":"
                            << std::endl;
                  std::perror("execl");
                  std::exit(1);
              }
          }
          return pid;
      }
      

      【讨论】:

      • 小修复:O_CREATE 应该是 O_CREAT 我相信你还需要直接使用 STDOUT_FILENO, STDERR_FILENO 而不是 stdout, stderr。
      • @XavierLeclercq 谢谢,修复了那些(加上缺少#includes)。
      猜你喜欢
      • 1970-01-01
      • 2010-11-23
      • 2023-04-02
      • 1970-01-01
      • 2012-07-04
      • 1970-01-01
      • 2022-12-14
      • 2013-06-02
      • 1970-01-01
      相关资源
      最近更新 更多