将exec输出重定向到缓冲区或文件

时间:2022-12-11 13:53:27

I'm writing a C program where I fork(), exec(), and wait(). I'd like to take the output of the program I exec'ed to write it to file or buffer.

我正在写一个C程序,我在fork(),exec()和wait()。我想把我执行的程序的输出写入文件或缓冲区。

For example, if I exec ls I want to write file1 file2 etc to buffer/file. I don't think there is a way to read stdout, so does that mean I have to use a pipe? Is there a general procedure here that I haven't been able to find?

例如,如果我执行ls我想将file1 file2等写入缓冲区/文件。我不认为有办法读取标准输出,所以这是否意味着我必须使用管道?这里有一个我无法找到的一般程序吗?

4 个解决方案

#1


69  

For sending the output to another file (I'm leaving out error checking to focus on the important details):

用于将输出发送到另一个文件(我要忽略错误检查以关注重要细节):

if (fork() == 0)
{
    // child
    int fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

    dup2(fd, 1);   // make stdout go to file
    dup2(fd, 2);   // make stderr go to file - you may choose to not do this
                   // or perhaps send stderr to another file

    close(fd);     // fd no longer needed - the dup'ed handles are sufficient

    exec(...);
}

For sending the output to a pipe so you can then read the output into a buffer:

要将输出发送到管道,您可以将输出读入缓冲区:

int pipefd[2];
pipe(pipefd);

if (fork() == 0)
{
    close(pipefd[0]);    // close reading end in the child

    dup2(pipefd[1], 1);  // send stdout to the pipe
    dup2(pipefd[1], 2);  // send stderr to the pipe

    close(pipefd[1]);    // this descriptor is no longer needed

    exec(...);
}
else
{
    // parent

    char buffer[1024];

    close(pipefd[1]);  // close the write end of the pipe in the parent

    while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
    {
    }
}

#2


12  

You need to decide exactly what you want to do - and preferably explain it a bit more clearly.

您需要确切地确定您想要做什么 - 并且最好更清楚地解释它。

Option 1: File

If you know which file you want the output of the executed command to go to, then:

如果您知道要执行的命令的输出要转到哪个文件,则:

  1. Ensure that the parent and child agree on the name (parent decides name before forking).
  2. 确保父母和孩子就名称达成一致(父母在分叉前决定姓名)。
  3. Parent forks - you have two processes.
  4. 父叉 - 你有两个过程。
  5. Child reorganizes things so that file descriptor 1 (standard output) goes to the file.
  6. Child重新组织事物,以便文件描述符1(标准输出)转到文件。
  7. Usually, you can leave standard error alone; you might redirect standard input from /dev/null.
  8. 通常,您可以单独留下标准错误;您可以从/ dev / null重定向标准输入。
  9. Child then execs relevant command; said command runs and any standard output goes to the file (this is the basic shell I/O redirection).
  10. 然后孩子执行相关命令;所述命令运行并且任何标准输出都转到该文件(这是基本的shell I / O重定向)。
  11. Executed process then terminates.
  12. 执行过程然后终止。
  13. Meanwhile, the parent process can adopt one of two main strategies:
    • Open the file for reading, and keep reading until it reaches an EOF. It then needs to double check whether the child died (so there won't be any more data to read), or hang around waiting for more input from the child.
    • 打开文件进行阅读,并继续阅读直至达到EOF。然后需要仔细检查孩子是否死亡(因此不会再有任何数据要阅读),或者等待孩子的更多输入。
    • Wait for the child to die and then open the file for reading.
    • 等待孩子死亡,然后打开文件进行阅读。
    • The advantage of the first is that the parent can do some of its work while the child is also running; the advantage of the second is that you don't have to diddle with the I/O system (repeatedly reading past EOF).
    • 第一个的优点是父母可以在孩子也在跑的时候做一些工作;第二个优点是您不必使用I / O系统(重复读取过去的EOF)。
  14. 同时,父进程可以采用以下两种主要策略之一:打开文件进行读取,并继续阅读直到达到EOF。然后需要仔细检查孩子是否死亡(因此不会再有任何数据要阅读),或者等待孩子的更多输入。等待孩子死亡,然后打开文件进行阅读。第一个的优点是父母可以在孩子也在跑的时候做一些工作;第二个优点是您不必使用I / O系统(重复读取过去的EOF)。

Option 2: Pipe

If you want the parent to read the output from the child, arrange for the child to pipe its output back to the parent.

如果您希望父级读取子级的输出,请安排子级将其输出传递回父级。

  1. Use popen() to do this the easy way. It will run the process and send the output to your parent process. Note that the parent must be active while the child is generating the output since pipes have a small buffer size (often 4-5 KB) and if the child generates more data than that while the parent is not reading, the child will block until the parent reads. If the parent is waiting for the child to die, you have a deadlock.
  2. 使用popen()以简单的方式完成此操作。它将运行该过程并将输出发送到您的父进程。请注意,在子节点生成输出时父节点必须处于活动状态,因为管道具有较小的缓冲区大小(通常为4-5 KB),并且如果子节点生成的数据多于父节点未读取的数据,则子节点将阻塞直到父母读。如果父母正在等待孩子死亡,那么你就会陷入僵局。
  3. Use pipe() etc to do this the hard way. Parent calls pipe(), then forks. The child sorts out the plumbing so that the write end of the pipe is its standard output, and ensures that all other file descriptors relating to the pipe are closed. This might well use the dup2() system call. It then executes the required process, which sends its standard output down the pipe.
  4. 使用pipe()等以这种方式做到这一点。 Parent调用pipe(),然后调用fork。孩子对管道进行分类,以便管道的写入端是其标准输出,并确保关闭与管道相关的所有其他文件描述符。这可能会使用dup2()系统调用。然后它执行所需的进程,将其标准输出发送到管道。
  5. Meanwhile, the parent also closes the unwanted ends of the pipe, and then starts reading. When it gets EOF on the pipe, it knows the child has finished and closed the pipe; it can close its end of the pipe too.
  6. 同时,父母也关闭管道的不需要的末端,然后开始阅读。当它在管道上获得EOF时,它知道孩子已经完成并关闭了管道;它也可以关闭管道的末端。

#3


2  

Since you look like you're going to be using this in a linux/cygwin environment, you want to use popen. It's like opening a file, only you'll get the executing programs stdout, so you can use your normal fscanf, fread etc.

既然你看起来要在linux / cygwin环境中使用它,你想要使用popen。这就像打开一个文件,只有你会得到执行程序标准输出,所以你可以使用正常的fscanf,fread等。

#4


1  

After forking, use dup2(2) to duplicate the file's FD into stdout's FD, then exec.

分叉后,使用dup2(2)将文件的FD复制到stdout的FD中,然后执行exec。

#1


69  

For sending the output to another file (I'm leaving out error checking to focus on the important details):

用于将输出发送到另一个文件(我要忽略错误检查以关注重要细节):

if (fork() == 0)
{
    // child
    int fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

    dup2(fd, 1);   // make stdout go to file
    dup2(fd, 2);   // make stderr go to file - you may choose to not do this
                   // or perhaps send stderr to another file

    close(fd);     // fd no longer needed - the dup'ed handles are sufficient

    exec(...);
}

For sending the output to a pipe so you can then read the output into a buffer:

要将输出发送到管道,您可以将输出读入缓冲区:

int pipefd[2];
pipe(pipefd);

if (fork() == 0)
{
    close(pipefd[0]);    // close reading end in the child

    dup2(pipefd[1], 1);  // send stdout to the pipe
    dup2(pipefd[1], 2);  // send stderr to the pipe

    close(pipefd[1]);    // this descriptor is no longer needed

    exec(...);
}
else
{
    // parent

    char buffer[1024];

    close(pipefd[1]);  // close the write end of the pipe in the parent

    while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
    {
    }
}

#2


12  

You need to decide exactly what you want to do - and preferably explain it a bit more clearly.

您需要确切地确定您想要做什么 - 并且最好更清楚地解释它。

Option 1: File

If you know which file you want the output of the executed command to go to, then:

如果您知道要执行的命令的输出要转到哪个文件,则:

  1. Ensure that the parent and child agree on the name (parent decides name before forking).
  2. 确保父母和孩子就名称达成一致(父母在分叉前决定姓名)。
  3. Parent forks - you have two processes.
  4. 父叉 - 你有两个过程。
  5. Child reorganizes things so that file descriptor 1 (standard output) goes to the file.
  6. Child重新组织事物,以便文件描述符1(标准输出)转到文件。
  7. Usually, you can leave standard error alone; you might redirect standard input from /dev/null.
  8. 通常,您可以单独留下标准错误;您可以从/ dev / null重定向标准输入。
  9. Child then execs relevant command; said command runs and any standard output goes to the file (this is the basic shell I/O redirection).
  10. 然后孩子执行相关命令;所述命令运行并且任何标准输出都转到该文件(这是基本的shell I / O重定向)。
  11. Executed process then terminates.
  12. 执行过程然后终止。
  13. Meanwhile, the parent process can adopt one of two main strategies:
    • Open the file for reading, and keep reading until it reaches an EOF. It then needs to double check whether the child died (so there won't be any more data to read), or hang around waiting for more input from the child.
    • 打开文件进行阅读,并继续阅读直至达到EOF。然后需要仔细检查孩子是否死亡(因此不会再有任何数据要阅读),或者等待孩子的更多输入。
    • Wait for the child to die and then open the file for reading.
    • 等待孩子死亡,然后打开文件进行阅读。
    • The advantage of the first is that the parent can do some of its work while the child is also running; the advantage of the second is that you don't have to diddle with the I/O system (repeatedly reading past EOF).
    • 第一个的优点是父母可以在孩子也在跑的时候做一些工作;第二个优点是您不必使用I / O系统(重复读取过去的EOF)。
  14. 同时,父进程可以采用以下两种主要策略之一:打开文件进行读取,并继续阅读直到达到EOF。然后需要仔细检查孩子是否死亡(因此不会再有任何数据要阅读),或者等待孩子的更多输入。等待孩子死亡,然后打开文件进行阅读。第一个的优点是父母可以在孩子也在跑的时候做一些工作;第二个优点是您不必使用I / O系统(重复读取过去的EOF)。

Option 2: Pipe

If you want the parent to read the output from the child, arrange for the child to pipe its output back to the parent.

如果您希望父级读取子级的输出,请安排子级将其输出传递回父级。

  1. Use popen() to do this the easy way. It will run the process and send the output to your parent process. Note that the parent must be active while the child is generating the output since pipes have a small buffer size (often 4-5 KB) and if the child generates more data than that while the parent is not reading, the child will block until the parent reads. If the parent is waiting for the child to die, you have a deadlock.
  2. 使用popen()以简单的方式完成此操作。它将运行该过程并将输出发送到您的父进程。请注意,在子节点生成输出时父节点必须处于活动状态,因为管道具有较小的缓冲区大小(通常为4-5 KB),并且如果子节点生成的数据多于父节点未读取的数据,则子节点将阻塞直到父母读。如果父母正在等待孩子死亡,那么你就会陷入僵局。
  3. Use pipe() etc to do this the hard way. Parent calls pipe(), then forks. The child sorts out the plumbing so that the write end of the pipe is its standard output, and ensures that all other file descriptors relating to the pipe are closed. This might well use the dup2() system call. It then executes the required process, which sends its standard output down the pipe.
  4. 使用pipe()等以这种方式做到这一点。 Parent调用pipe(),然后调用fork。孩子对管道进行分类,以便管道的写入端是其标准输出,并确保关闭与管道相关的所有其他文件描述符。这可能会使用dup2()系统调用。然后它执行所需的进程,将其标准输出发送到管道。
  5. Meanwhile, the parent also closes the unwanted ends of the pipe, and then starts reading. When it gets EOF on the pipe, it knows the child has finished and closed the pipe; it can close its end of the pipe too.
  6. 同时,父母也关闭管道的不需要的末端,然后开始阅读。当它在管道上获得EOF时,它知道孩子已经完成并关闭了管道;它也可以关闭管道的末端。

#3


2  

Since you look like you're going to be using this in a linux/cygwin environment, you want to use popen. It's like opening a file, only you'll get the executing programs stdout, so you can use your normal fscanf, fread etc.

既然你看起来要在linux / cygwin环境中使用它,你想要使用popen。这就像打开一个文件,只有你会得到执行程序标准输出,所以你可以使用正常的fscanf,fread等。

#4


1  

After forking, use dup2(2) to duplicate the file's FD into stdout's FD, then exec.

分叉后,使用dup2(2)将文件的FD复制到stdout的FD中,然后执行exec。