Bash Pipe Handling


29

有谁知道bash如何处理通过管道发送数据?

cat file.txt | tail -20 

该命令是否将file.txt的所有内容打印到缓冲区中,然后通过尾部读取?或者这个命令,比如说,逐行打印file.txt的内容,然后在每一行中暂停处理尾部,然后询问更多的数据?

我问的原因是我正在一个嵌入式设备上编写一个程序,该程序基本上对一些数据块执行一系列操作,其中一个操作的输出作为下一个操作的输入发送。我想知道linux(bash)如何处理这个问题,所以请给我一个普遍的答案,不是特别是当我运行“cat file.txt | tail -20”时会发生什么。

预先感谢您的回复!

编辑:Shog9指出了一个有关的维基百科文章,这并没有直接引导我到文章,但它帮助我找到这个:http://en.wikipedia.org/wiki/Pipeline_%28Unix%29#Implementation哪些确实有我正在寻找的信息。


对不起,我没有让自己清楚。当然你使用的是管道,当然你使用的是命令各个部分的stdin和stdout。我认为这太明显了,无法说明。

我在问的是如何处理/实施。由于这两个程序不能同时运行,数据如何从标准输入发送到标准输出?如果第一个程序产生的数据比第二个程序快得多,会发生什么?系统是否只运行第一个命令,直到终止或stdout缓冲区已满为止,然后继续执行下一个程序,依此类推,直到没有更多数据需要处理或存在更复杂的机制?

54

我决定写一个稍微更详细的解释。

这里的“魔术”在于操作系统。这两个程序大致同时启动,并且与您的计算机上的其他每个同时运行的进程(包括终端应用程序和内核)同时运行(操作系统在处理器上分配它们的时间片) 。所以,在任何数据通过之前,这些进程正在做任何必要的初始化。在你的例子中,tail解析'-20'参数,cat解析'file.txt'参数并打开文件。在某些点尾部会达到需要输入的地步,它会告诉操作系统它正在等待输入。在其他一些地方(无论是之前还是之后,这并不重要),cat将开始使用stdout将数据传递到操作系统。这进入操作系统的缓冲区。下一次,当一些数据被cat放入缓冲区后,尾部会在处理器上获得一个时间片,它将检索一些数据(或全部数据),这些数据会在操作系统上离开缓冲区。当缓冲区为空时,在某个点尾部必须等待cat输出更多数据。如果cat输出的数据比tail处理数据快得多,缓冲区将会扩大。cat最终会输出数据,但尾部仍然会被处理,所以cat会关闭,尾部会处理缓冲区中的所有剩余数据。当操作系统的EOF数据不再有输入时,操作系统会发出信号尾。尾巴将处理剩余的数据。在这种情况下,tail可能只是将所有数据接收到20行的循环缓冲区中,并且当操作系统发出信号指示没有更多传入数据时,它会将最后20行转储到它自己的stdout,只是显示在终端中。由于tail比cat更简单,它可能会花费大部分时间等待cat将数据放入缓冲区。

在具有多个处理器的系统上,这两个程序不会在同一个处理器核心上共享交替时间片,而是可能同时在不同的核心上运行。为了更详细地介绍一下,如果你在Linux中打开某种进程监视器(特定于操作系统),比如'top',你将看到一个正在运行的进程列表,其中大部分列表正在使用0%的处理器。大多数应用程序,除非正在处理数据,否则大部分时间都是无所事事。这很好,因为它允许其他进程根据自己的需要无限制地访问处理器。这基本上以三种方式完成。一个进程可以得到一个睡眠(n)式指令,它基本上告诉内核等待n毫秒,然后再给它一个时间片来处理。大多数情况下,程序需要等待其他程序的某些内容,例如等待更多数据进入缓冲区的“尾部”。在这种情况下,当有更多数据可用时,操作系统将唤醒进程。最后,内核可以在执行过程中抢占进程,为其他进程提供一些处理器时间片。 '猫'和'尾巴'是简单的程序。在这个例子中,尾巴花费大部分时间等待缓冲区中的更多数据,并且猫花费大部分时间等待操作系统从硬盘中检索数据。瓶颈是文件存储在物理介质上的速度(或缓慢)。第一次运行此命令时可能检测到的可感知延迟是磁盘驱动器上的读取磁头寻找“file.txt”所在硬盘上的位置所需的时间。如果您再次运行此命令,操作系统可能会将file.txt的内容缓存到内存中,并且您不可能看到任何可感知的延迟(除非file.txt非常大或文件不再被缓存)

您在计算机上执行的大多数操作都是IO绑定的,也就是说您通常会等待数据来自硬盘或网络设备等。


0

cat只会将数据打印到标准输出中,恰好被重定向到尾部的标准。这可以在bash的man页面中看到。

换句话说,没有暂停进行,尾巴只是从标准中读取,而猫只是写入标准。


1

Shog9已经引用了维基百科的文章,但implementation section有你想要的细节。基本的实现是一个有界的缓冲区。