【问题标题】:How does a pipe work in Linux?管道在 Linux 中是如何工作的?
【发布时间】:2010-11-07 12:17:25
【问题描述】:

管道如何工作?如果我通过 CLI 运行一个程序并将输出重定向到一个文件,我是否能够在编写该文件时将该文件传送到另一个程序中?

基本上,当将一行写入文件时,我希望它立即通过管道传输到我的第二个应用程序(我正在尝试从现有程序动态绘制图形)。只是不确定管道是否在继续执行下一个命令之前完成了第一个命令。

任何反馈将不胜感激!

【问题讨论】:

  • 您在下面提到了 program1 的 CLI 接口 - 如果 program1 依赖于交互式输入,那么它可能不适合像 Adam 的回答那样直接管道。
  • windows 中的管道与 Linux 中的管道不同...我相信 Linux 使用某种类型的环形缓冲区并使用并发编程理论(生产者-消费者问题等)来表现良好。我认为 Windows 会等到第一个程序完成后再调用第二个。

标签: c linux redirect pipe


【解决方案1】:

如果你想将一个程序的输出重定向到另一个程序的输入,只需使用一个简单的管道:

program1 arg arg | program2 arg arg

如果您想将program1 的输出保存到文件中将其通过管道传输到program2,您可以使用tee(1)

program1 arg arg | tee output-file | program2 arg arg

管道中的所有程序同时运行。大多数程序通常使用阻塞 I/O:如果当它们尝试读取输入但没有任何内容时,它们阻塞:也就是说,它们会停止,并且操作系统会停止- 安排它们运行,直到有更多输入可用(以避免占用 CPU)。类似地,如果管道中较早的程序写入数据的速度比后面的程序读取数据的速度快,最终管道的缓冲区会填满并且写入器阻塞:操作系统会取消调度它,直到管道的缓冲区被读取器清空,然后又可以继续写了。


编辑

如果您想使用program1 的输出作为命令行参数,您可以使用反引号或$() 语法:

# Runs "program1 arg", and uses the output as the command-line arguments for
# program2
program2 `program1 arg`

# Same as above
program2 $(program1 arg)

应该首选$() 语法,因为它们更清晰,并且可以嵌套。

【讨论】:

  • 由于某种原因,初始程序(在本例中为 program1)不与管道配合使用。里面是否需要特殊代码?我尝试按照您的布局做一个简单的管道,1)program1 的 CLI 接口没有启动,2)program2 要求提供参数(尽管我试图将 1 的输出作为 2 的参数传递)
  • @Jon,听起来 program1 没有将其输出发送到 stdout,或者 program2 没有从 stdin 读取。你想运行什么程序?
  • 有些程序可以读取一个标志来确定它们是否在管道中......'ls'这样做是为了决定如何显示文件信息(当在管道中时,它每个文件都有自己的一行等)
  • @Matt,我使用了管道和回声手册页中列出的示例。我假设这需要输入,然后打印两次或至少一次。不是这样。我的 CLI 看起来像 $./test "testing" |回声。测试基本上只是一个程序,将字符串放入管道中,然后逐个字符地将其拉出。
  • @Jon: echo 不读取它的标准输入,它只查看它的命令行参数。你到底想做什么?
【解决方案2】:

管道在运行第二个命令之前未完成第一个命令。 Unix(和 Linux)管道同时运行所有命令。如果

  • 它急需输入。

  • 它产生的输出比它的继任者准备消耗的要多得多。

对于大多数程序的输出是缓冲的,这意味着操作系统在将其传递到管道的下一个阶段之前会累积大量输出(可能是 8000 个字符左右)。这种缓冲用于避免过多地在进程和内核之间来回切换。

如果您希望立即发送管道上的输出,您可以使用 unbuffered I/O,这在 C 中意味着调用类似 fflush() 的东西来确保任何缓冲输出都是 立即发送到下一个过程。无缓冲输入也是可能的,但通常是不必要的,因为缺乏输入的进程通常不会等待完整的缓冲区,而是会处理您可以获得的任何输入。

对于典型应用,不推荐使用无缓冲输出;您通常会使用默认值获得最佳性能。但是,在您的情况下,如果您想立即进行动态绘图,则第一个进程有可用的信息,您肯定希望使用无缓冲的输出。如果你使用 C,只要你想发送输出就调用fflush(stdout) 就足够了。

【讨论】:

    【解决方案3】:

    如果您的程序使用stdinstdout 进行通信,那么请确保您在写入后调用fflush(stdout),或者找到某种方法来禁用标准IO 缓冲。我能想到的真正描述如何在 C/C++ 中最好地实现管道的最佳参考是 Advanced Programming in the UNIX EnvironmentUNIX Network Programming: Volume 2。您也可以从 this article 开始。

    【讨论】:

      【解决方案4】:

      如果你的两个程序坚持读写文件而不使用标准输入/标准输出,你可能会发现你可以使用命名管道来代替文件。

      使用 mknod(1) 命令创建命名管道:

      $ mknod /tmp/named-pipe p
      

      然后配置您的程序以读取和写入 /tmp/named-pipe(使用您认为合适的任何路径/名称)。

      在这种情况下,两个程序将并行运行,并在管道变满/空时根据需要阻塞,如其他答案中所述。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-25
        • 2014-09-08
        • 2018-12-29
        • 1970-01-01
        • 1970-01-01
        • 2015-02-08
        • 1970-01-01
        • 2014-07-18
        相关资源
        最近更新 更多