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

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

  •  34
  • devin  · 技术社区  · 15 年前

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

    例如,如果我执行 ls 我想写 file1 file2 etc 缓冲区/文件。我不认为有什么方法可以读取stdout,那是否意味着我必须使用管道?这里有我找不到的一般程序吗?

    4 回复  |  直到 9 年前
        1
  •  75
  •   R Samuel Klatchko    15 年前

    将输出发送到另一个文件(我不做错误检查,只关注重要的细节):

    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)
        {
        }
    }
    
        2
  •  14
  •   Jonathan Leffler    15 年前

    你需要准确地决定你想做什么——最好解释得更清楚一点。

    选项1:文件

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

    1. 确保父级和子级在名称上达成一致(父级在分叉前决定名称)。
    2. 父分叉-您有两个进程。
    3. 子级重新组织内容,使文件描述符1(标准输出)转到文件。
    4. 通常,您可以只保留标准错误;您可以将标准输入从/dev/null重定向。
    5. 然后,child执行相关的命令;所述命令运行,任何标准输出都将转到文件(这是基本的shell I/O重定向)。
    6. 然后执行进程终止。
    7. 同时,父进程可以采用两种主要策略之一:
      • 打开文件进行读取,并继续读取直到达到EOF。然后,它需要再次检查孩子是否死亡(这样就不会有更多的数据需要读取),或者等待孩子的更多输入。
      • 等待孩子死去,然后打开文件阅读。
      • 第一种方法的优点是,当孩子也在运行时,家长可以完成一些工作;第二种方法的优点是,您不必在I/O系统上浪费时间(反复读取EOF)。

    方案2:管道

    如果希望父级从子级读取输出,请安排子级将其输出通过管道返回父级。

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

    因为您看起来要在Linux/Cygwin环境中使用它,所以您希望使用 popen . 就像打开一个文件,只有你能得到正在执行的程序 stdout ,这样你就可以使用正常的 fscanf , fread 等。

        4
  •  1
  •   Ignacio Vazquez-Abrams    15 年前

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