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

cat file.txt | tail -20

该命令是否将 file.txt 的所有内容打印到缓冲区中,然后通过 tail 读取该缓冲区?或者这个命令是否逐行打印 file.txt 的内容,然后在每一行暂停以便 tail 处理,然后请求更多数据?

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

预先感谢您的回复!

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


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

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

有帮助吗?

解决方案

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

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

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

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

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

其他提示

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top