【问题标题】:Why is it not possible to replace stdout with pipe output directly?为什么不能直接用管道输出替换标准输出?
【发布时间】:2021-09-09 09:40:26
【问题描述】:

我想将子进程的输出通过管道传输到父进程的stdout。我知道还有其他方法可以做到这一点,但为什么管道的读取端不能复制到stdout为什么程序不打印写入管道写入端的内容?

在这里,我有一个我正在尝试做的最小示例(没有任何子流程)。我希望在运行时在输出中看到test,但程序什么也没输出。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
    int fds[2];
    if(pipe(fds) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    if(write(fds[1], "test", 5) == -1) {
        perror("write");
        exit(EXIT_FAILURE);
    }

    if(dup2(fds[0], STDOUT_FILENO) == -1) {
        perror("dup2");
        exit(EXIT_FAILURE);
    }

    return 0;
}

【问题讨论】:

  • 我认为您需要在dup2 之前close(STDOUT_FILENO)。您还应该检查dup2 是否失败(if dup2(fds[0], STDOUT_FILENO) == -1) {handle error})。
  • STDOUT_FILENO 由子(分叉?)进程继承。为什么不直接给孩子写STDOUT_FILENO呢?
  • @Jabberwocky dup2() 自动关闭 STDOUT_FILENO。如果我使用 dup(),那将是真的。
  • @tstanisl 这不是如何修复的问题,我更想知道为什么这是不可能的。
  • 所以问题是关于将两个现有文件描述符加入管道?

标签: c pipe stdout


【解决方案1】:

管道是两个“文件”,它们共享一个缓冲区和一些锁定或控制语义。当您写入管道时,数据被放入缓冲区。当您从管道中读取数据时,数据会从缓冲区中获取。

管道中没有任何东西可以将数据移动到某个输出设备。

如果您使用dup2 将管道的读取端复制到标准输出文件描述符(编号 1)中,那么您所拥有的只是文件描述符 1 上管道的读取端。这意味着您可以发出 read对文件描述符 1 进行操作,系统会从管道中给你的程序数据。

在这方面,文件描述符 1 并没有什么“特别”之处。将任何文件放在文件描述符 1 上不会导致该文件自动发送到任何地方。标准输出正常工作的方式是,您在文件描述符 1 上打开终端或某些选定的输出文件或其他设备,然后通过写入文件描述符 1 将内容发送到该设备或文件。操作系统不会自动写入内容到文件描述符 1;你必须发出写操作。

【讨论】:

  • 感谢您的详尽解答!父子关系如何运作?默认情况下,孩子的标准输出被转发给父母。你的意思是这不能用管道实现?这是怎么做的?
  • @Olle:当一个进程被分叉时,子进程和父进程只会打开相同的文件。这不是将孩子的标准输出转发到父母的问题。如果父级在分叉时将其标准输出(文件描述符 1)打开到终端或文件,则子级将其标准输出(文件描述符 1)打开到相同的终端或文件。
  • 我现在明白了。谢谢!
猜你喜欢
  • 1970-01-01
  • 2018-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多