简体   繁体   English

是否可以将子进程的标准输出重定向到父进程中的另一个文件?

[英]Is it possible to redirect child process's stdout to another file in parent process?

A child process runs a bin file, which is provided by Qualcomm.子进程运行一个 bin 文件,该文件由 Qualcomm 提供。 The child process is invoked by my parent process, which is developed by me.子进程由我开发的父进程调用。 When the child process is running, it always prints lots pieces of logs in shell command.当子进程运行时,它总是在shell命令中打印大量日志。 So, am I able to redirect Qualcomm's outstream from stdout to another file in the parent process?那么,我是否能够将 Qualcomm 的输出从 stdout 重定向到父进程中的另一个文件? As you know, it's nearly impossible to push Qualcomm to update this bin file.如你所知,推动高通更新这个bin文件几乎是不可能的。 Thanks a lot~非常感谢~

The key piece here is the POSIX function dup2 , which lets you essentially replace one file descriptor with another.这里的关键部分是 POSIX 函数dup2 ,它让您基本上可以用另一个文件描述符替换一个文件描述符。 And if you use fork (not system ), you actually have control of what happens in the child process between the fork and the exec* that loads the other executable.如果您使用fork (而不是system ),您实际上可以控制在fork和加载其他可执行文件的exec*之间的子进程中发生的事情。

#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;
}

It is possible, for POSIX, because the POSIX shells do this.对于 POSIX,这是可能的,因为 POSIX shell 会这样做。 Executing a program has two steps, for POSIX.对于 POSIX,执行程序有两个步骤。 First use fork to clone the parent process to create the child process.首先使用fork克隆父进程创建子进程。 Then have the child process use one of the exec family of system calls to execute the chosen program instead of the program of the parent.然后让子进程使用 exec 系列系统调用之一来执行所选程序而不是父进程。 In between those two steps the code executing for the child process can do additional operations, which will affect the environment of the program to be executed.在这两个步骤之间,为子进程执行的代码可以执行额外的操作,这将影响要执行的程序的环境。 In particular, the code could open a file descriptor to the file to be redirected to, close the stdout file descriptor, then duplicate the file's file descriptor to the value (1) used for stdout.特别是,代码可以打开要重定向到的文件的文件描述符,关闭 stdout 文件描述符,然后将文件的文件描述符复制到用于 stdout 的值 (1)。

You could create own pipes and attach them to the child process.您可以创建自己的管道并将它们附加到子进程。

  1. Create 3 pipes.创建 3 个管道。 they are going to replace stdin, stdout, stderr of the child.他们将替换孩子的 stdin、stdout、stderr。
  2. fork()
  3. In subprocess close() the parent end of the pipes.在子进程close()中管道的父端。 Close stdin,stdout and stderr.关闭标准输入、标准输出和标准错误。
  4. The parent process close() the child end of the pipes.父进程close()管道的子端。
  5. dup2() the pipe ends in the child process that are intended to work as the new stdin,out,err dup2()管道在子进程中结束,该子进程旨在用作新的 stdin,out,err
  6. exec() the child. exec()孩子。

Now you got all Output from the child to the pipe in the parent.现在您获得了从孩子到父母管道的所有输出。 Ofcourse you need to read from the pipes that come from the child or it will block on any write to the stdout/stderr.当然,您需要从来自孩子的管道中读取数据,否则它会阻止对 stdout/stderr 的任何写入。 For this you could use a select() , poll() , epoll() multiplexing algorithm.为此,您可以使用select()poll()epoll()多路复用算法。

See

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

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

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM