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

时间:2010-04-09 04:43:34

标签: c exec fork

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

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

5 个答案:

答案 0 :(得分:79)

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

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(...);
}

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

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)
    {
    }
}

答案 1 :(得分:14)

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

选项1:文件

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

  1. 确保父母和孩子就名称达成一致(父母在分叉前决定姓名)。
  2. 父叉 - 您有两个流程。
  3. Child重新组织事物,以便文件描述符1(标准输出)转到文件。
  4. 通常,您可以单独留下标准错误;您可以从/ dev / null重定向标准输入。
  5. 孩子然后执行相关命令;所述命令运行并且任何标准输出都转到该文件(这是基本的shell I / O重定向)。
  6. 执行过程然后终止。
  7. 同时,父进程可采用以下两种主要策略之一:
    • 打开文件进行阅读,并继续阅读,直至达到EOF。然后需要仔细检查孩子是否死亡(因此不会再有任何数据可供阅读),或者等待孩子提供更多的意见。
    • 等待孩子死亡,然后打开文件进行阅读。
    • 第一个的优点是父母可以在孩子也在跑的时候做一些工作;第二个优点是您不必使用I / O系统(重复读取过去的EOF)。
  8. 选项2:管道

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

    1. 使用popen()以简单的方式完成此操作。它将运行该进程并将输出发送到您的父进程。请注意,在子节点生成输出时父节点必须处于活动状态,因为管道具有较小的缓冲区大小(通常为4-5 KB),并且如果子节点生成的数据多于父节点未读取的数据,则子节点将阻塞直到父母读。如果父母正在等待孩子死亡,那么你就陷入了僵局。
    2. 使用pipe()等以这种方式做到这一点。 Parent调用pipe(),然后调用fork。孩子对管道进行分类,以便管道的写入端是其标准输出,并确保关闭与管道相关的所有其他文件描述符。这可能会使用dup2()系统调用。然后它执行所需的进程,将其标准输出发送到管道。
    3. 同时,父母也关闭管道的不需要的一端,然后开始阅读。当它在管道上获得EOF时,它知道孩子已经完成并关闭了管道;它也可以关闭管道的末端。

答案 2 :(得分:2)

由于您似乎要在linux / cygwin环境中使用它,因此您希望使用popen。这就像打开一个文件一样,只有你才能获得正在执行的程序stdout,这样你就可以使用正常的fscanffread等。

答案 3 :(得分:1)

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

答案 4 :(得分:1)

您还可以使用linux sh命令,并将包含重定向的命令传递给它:

string cmd = "/bin/ls > " + filepath;

execl("/bin/sh", "sh", "-c", cmd.c_str(), 0);
相关问题