30

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

cat file.txt | tail -20

此命令是否将 file.txt 的所有内容打印到缓冲区中,然后由 tail 读取?还是这个命令,比如说,逐行打印 file.txt 的内容,然后在每一行暂停以便 tail 处理,然后要求更多数据?

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

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


我很抱歉没有说清楚。当然,您正在使用管道,当然您正在使用命令各个部分的标准输入和标准输出。我以为这太明显了,无法说明。

我要问的是如何处理/实施。既然两个程序都不能同时运行,那么数据是如何从标准输入发送到标准输出的呢?如果第一个程序生成数据的速度明显快于第二个程序会怎样?系统是否只运行第一个命令直到它被终止或者它的标准输出缓冲区已满,然后继续执行下一个程序,等等循环直到没有更多数据需要处理或者是否有更复杂的机制?

4

3 回答 3

55

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

这里的“魔力”在于操作系统。两个程序确实在大致相同的时间启动,并且与计算机上所有其他同时运行的进程(包括终端应用程序和内核)同时运行(操作系统为它们分配处理器上运行的时间片) . 因此,在任何数据通过之前,进程都会进行必要的初始化。在您的示例中,tail 正在解析“-20”参数,而 cat 正在解析“file.txt”参数并打开文件。在某个时刻,tail 会到达需要输入的位置,它会告诉操作系统它正在等待输入。在其他某个时间点(无论是之前还是之后,都无所谓)cat 将开始使用标准输出将数据传递给操作系统。这进入操作系统中的缓冲区。在 cat 将一些数据放入缓冲区后,tail 下一次在处理器上获得一个时间片,它将检索一些数据(或全部),这些数据将缓冲区留在操作系统上。当缓冲区为空时,tail 将不得不等待 cat 输出更多数据。如果 cat 输出数据的速度比 tail 处理数据的速度快得多,则缓冲区将扩大。cat 最终将完成输出数据,但 tail 仍在处理中,因此 cat 将关闭并且 tail 将处理缓冲区中的所有剩余数据。当没有带有 EOF 的传入数据时,操作系统将发出尾部信号。Tail 将处理剩余的数据。在这种情况下,tail 可能只是将所有数据接收到一个 20 行的循环缓冲区中,当操作系统发出没有更多输入数据的信号时,它会将最后二十行转储到自己的标准输出中,该标准输出只会显示在终端中。由于 tail 是一个比 cat 简单得多的程序,它可能会花费大部分时间等待 cat 将数据放入缓冲区。

在具有多个处理器的系统上,这两个程序不仅会在同一个处理器内核上共享交替的时间片,而且很可能同时在不同的内核上运行。

更详细地说,如果您在 Linux 中打开某种进程监视器(特定于操作系统),例如“top”,您将看到正在运行的进程的完整列表,其中大多数有效地使用了 0% 的处理器。大多数应用程序,除非它们正在处理数据,否则大部分时间都在无所事事。这很好,因为它允许其他进程根据需要不受限制地访问处理器。这基本上通过三种方式完成。一个进程可以进入一个 sleep(n) 风格的指令,它基本上告诉内核在给它另一个时间片之前等待 n 毫秒。最常见的是一个程序需要等待另一个程序的某些东西,比如'tail'等待更多数据进入缓冲区。在这种情况下,当有更多数据可用时,操作系统将唤醒进程。最后,内核可以在执行过程中抢占一个进程,给其他进程一些处理器时间片。'cat' 和 'tail' 是简单的程序。在此示例中,tail 大部分时间都在等待缓冲区上的更多数据,而 cat 大部分时间都在等待操作系统从硬盘中检索数据。瓶颈是存储文件的物理介质的速度(或缓慢)。当您第一次运行此命令时,您可能会检测到的可察觉延迟是磁盘驱动器上的读取磁头寻找到硬盘驱动器上“file.txt”所在位置所需的时间。如果您再次运行该命令,

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

于 2008-08-21T05:46:23.337 回答
1

Shog9 已经引用了 Wikipedia 文章,但实现部分有您想要的详细信息。基本实现是有界缓冲区。

于 2008-08-21T01:45:20.220 回答
0

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

换句话说,没有暂停,tail 只是从标准输入读取,而 cat 只是写入标准输出。

于 2008-08-21T00:29:00.153 回答