管道命令以什么顺序运行?

act*_*ato 109 pipe ps

我从来没有真正考虑过 shell 是如何实际执行管道命令的。我一直被告知“一个程序的标准输出通过管道传输到另一个程序的标准输入中”,这是对管道的一种思考方式。所以很自然地,我认为在 say 的情况下,A | B,A将首先运行,然后B获取 的标准输出A,并使用标准输出A作为其输入。

但我注意到,当人们搜索特定的工艺ps,他们会包括grep -v "grep"在命令的末尾,以确保grep不会出现在最终的输出。
这意味着在命令ps aux | grep "bash" | grep -v "grep"中暗示ps知道grep正在运行,因此在ps. 但是如果ps在它的输出通过管道传输到 之前完成运行,它grep怎么知道它grep正在运行?

flamingtoast@FTOAST-UBUNTU: ~$ ps | grep ".*"
PID TTY          TIME CMD
3773 pts/0    00:00:00 bash
3784 pts/0    00:00:00 ps
3785 pts/0    00:00:00 grep
Run Code Online (Sandbox Code Playgroud)

Gil*_*il' 79

管道命令并发运行。当你运行ps | grep …,这是抽签的运气(或外壳与内核的肠子调度微调深相结合的工作的细节问题)是否psgrep首次启动时,在任何情况下,他们继续同时执行。

这通常用于允许第二个程序在第一个程序完成其操作之前处理来自第一个程序的数据。例如

grep pattern very-large-file | tr a-z A-Z
Run Code Online (Sandbox Code Playgroud)

甚至在grep完成对大文件的遍历之前,就开始以大写形式显示匹配的行。

grep pattern very-large-file | head -n 1
Run Code Online (Sandbox Code Playgroud)

显示第一个匹配行,并且可能在grep完成读取其输入文件之前停止处理。

如果您在某处读到管道程序按顺序运行,请远离本文档。管道程序并发运行并且始终具有。

  • 这个例子很酷的是,当 head 得到它需要的一行时,它会终止,当 grep 注意到这一点时,它也会终止而不做一堆进一步的工作。 (9认同)
  • @naxa 实际上有两个缓冲区。`grep` 程序中有 [stdio](http://en.wikipedia.org/wiki/Stdio) 缓冲区,管道本身有一个由内核管理的缓冲区。对于后者,请参阅[管道缓冲区有多大?](http://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer) (4认同)

Kyl*_*nes 52

命令运行的顺序实际上无关紧要,也不能保证。撇开pipe(), fork(),dup()和的神秘细节不谈execve(),外壳首先创建管道,即数据在进程之间流动的管道,然后创建将管道末端连接到它们的进程。运行的第一个进程可能会阻塞等待第二个进程的输入,或者阻塞等待第二个进程开始从管道读取数据。这些等待可以是任意长的并且无关紧要。无论进程以何种顺序运行,数据最终都会被传输并且一切正常。

  • 不错的答案,但 OP 似乎认为流程是按顺序运行的。您可能会在此处更清楚地说明这些过程是同时运行的,并且管道就像......桶之间的管道,水在(大约)同一时间流过所有管道。 (5认同)

Sco*_*ott 36

冒着打败死马的风险,误解似乎是

    一个| 

相当于

    A >临时文件
    B <临时文件
    rm临时文件

但是,在创建 Unix 并且孩子们骑着恐龙上学时,磁盘非常小,并且一个相当温和的命令消耗文件系统中的所有可用空间是很常见的。如果B是像 ,管道的最终输出可以是比中间文件更小。因此,管道的开发不是作为“先运行A,然后使用A输出的输入运行B ”模型的简写,而是作为一种与 中间文件并发执行并消除存储中间文件的需要的方式磁盘上。grep some_very_obscure_stringBA