Linux 实用程序在运行管道命令时是否智能?

Linux 实用程序在运行管道命令时是否智能?

我刚刚在终端中运行了几个命令,我开始想知道,Unix/Linux 在运行管道命令时是否采用快捷方式?

例如,假设我有一个包含 100 万行的文件,其中前 10 行包含hello world.如果运行该命令,grep "hello world" file | head第一个命令是否会在找到 10 行后立即停止,还是会先继续搜索整个文件?

答案1

有点。 shell 不知道您正在运行的命令将执行什么操作,它只是将一个命令的输出连接到另一个命令的输入。

如果grep找到超过 10 行“hello world”,head则将获得所需的所有 10 行,并关闭管道。这将导致grep被 SIGPIPE 杀死,因此不需要继续扫描非常大的文件。

答案2

当程序尝试写入管道并且没有进程从该管道读取时,写入程序会收到信号管道信号。当程序收到 SIGPIPE 时,默认操作是终止该程序。程序可以选择忽略 SIGPIPE 信号,在这种情况下写入会返回错误 ( EPIPE)。

在您的示例中,以下是发生情况的时间表:

  • grep命令head并行启动。
  • grep读取一些输入,开始处理它。
  • 在某个时刻,grep产生第一个输出块。
  • head读取第一个块并将其写出。
  • 假设前 10 场比赛后有足够的行(否则grep可能会先终止),最终head将打印出所需的行数。此时,head退出。
  • 根据grephead进程的相对速度,grep可能已经积累了一些数据但尚未打印出来。退出时headgrep可能正在读取输入或进行内部处理,在这种情况下它将继续这样做。
  • 很快grep就会写出它处理过的数据。此时,它将收到 SIGPIPE 并死亡。

它可能grep会处理比严格必要的输入多一点的输入,但通常只有几千字节:

  • head通常以几千字节的块读取(因为这比read为每个字节发出系统调用更有效 - 这种行为称为缓冲),因此在所需的最后一行之后的最后一个块的剩余部分将被丢弃。
  • 可能有一些数据正在传输,因为管道有一个由内核管理的关联缓冲区(通常为 512 字节)。该数据将被丢弃。
  • grep可能已经积累了一些数据,准备成为输出块(再次缓冲)。当它尝试刷新其输出缓冲区时,它将收到 SIGPIPE。

总而言之,该系统经过精确设计,因此过滤实用程序自然可以高效运行。当输出通道消失时需要继续运行的程序必须采取忽略 SIGPIPE 信号的步骤。

答案3

某种程度上,管道的工作原理是这样的:它首先执行第一个命令,然后在您的情况下执行第二个命令。

也就是说,让我们成为A|B所给出的命令。那么到底是AorB先启动就不确定了。如果有多个 CPU,它们可能会同时启动。管道可以容纳未定义但有限数量的数据。

如果 B 尝试从管道中读取数据,但没有可用数据,B则将等待数据到达。如果B是从磁盘读取,B可能会遇到同样的问题,需要等待磁盘读取完成。更接近的类比是从键盘上读取。在那里,B需要等待用户输入。但在所有这些情况下,B 已开始“读取”操作,并且必须等待其完成。但是 ifB是一个命令,只需要Athen 的部分输出,在B达到 s 输入级别的某个点之后A将被 SIGPIPE 终止

如果A尝试写入管道并且管道已满,A则必须等待管道中的一些空间空闲。A如果写入终端,可能会出现同样的问题。终端具有流量控制功能并且可以调节数据的速度。无论如何A,它已经启动了“写入”操作,并将等待写入操作完成。

AB表现为协同进程,尽管并非所有协同进程都会与管道进行通信。双方都无法完全控制对方。

答案4

grep没有对管道的直接控制(它只是接收数据),并且管道没有直接控制grep(它只是发送数据)...

或任何其他程序做什么grep,完全取决于该程序的内部逻辑。如果您grep通过命令行选项告知尽早进行找到后退出,那么它就会,否则它将继续到文件的最后寻找模式......

终端同样与 的内部运作grepshell管道操作完全脱节...终端基本上只是一个发射台和输出显示...

相关内容