我从来没有真正考虑过shell如何实际执行管道命令。一直有人告诉我,“一个程序的标准输出通过管道传递到另一个程序的标准输入”,作为思考管道的一种方式。因此,自然而然地,我认为在先运行A | BA的情况下,然后B获得A的标准输出,并使用A的标准输出作为其输入。

但是我注意到,当人们在ps中搜索特定过程时,他们会在命令末尾包含grep -v "grep",以确保grep不会出现在最终输出中。 br />这意味着在命令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


评论

为什么不接受答案?

#1 楼

管道命令同时运行。当您运行ps | grep …时,是先决定ps还是grep开始,这是抽奖的运气(或者说是shell的工作原理与调度程序的结合,它深入内核的深处)。它们继续并发执行。

这是非常常用的方法,它允许第二个程序在第一个程序完成其操作之前处理从第一个程序发出的数据。例如,

grep pattern very-large-file | tr a-z A-Z


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

grep pattern very-large-file | head -n 1


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

如果您在某个地方读取到按顺序运行管道程序的信息,请退出此文档。管道程序可以同时运行,并且始终运行。

评论


这个示例的有趣之处在于,当head获得所需的一行时,它终止,并且当grep注意到这一点时,它也终止了,而无需进行任何其他工作。

–乔
2012年5月5日20:48

我想关于管道有某种IO缓冲区...我怎么知道它的大小(以字节为单位)?我想阅读以了解更多信息? :)

–n611x007
13年11月24日在21:14

@naxa实际上有两个缓冲区。 grep程序中有stdio缓冲区,而管道本身中有一个由内核管理的缓冲区。对于后者,请参阅管道缓冲区有多大?

–吉尔斯'所以-不再是邪恶的'
13年11月24日在21:29

#2 楼

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

评论


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

–基思
2012年4月28日下午6:16

谢谢你的澄清。我一直在阅读的资源使管道程序看起来像是顺序运行,而不是并发运行。

–action_potato
2012年4月28日在7:58

要查看以不确定的方式开始的进程,请尝试运行1000次:echo -n a>&2 |回声b>&2

–奥雷·丹吉(Ole Tange)
16年5月4日在7:43

也许是一个幼稚的问题...第一个进程是否被阻塞/正在等待第二个进程(以获取零件信息),需要做什么?但是,管道必须是双向的吗?

–stdout
20-09-26在15:38

@stdout如果写入过程被阻止,则是因为管道已满,并且读取过程需要从管道中读取一些数据,以便有空间。如果读取过程被阻止,那是因为管道为空,并且写入过程需要将一些数据写入管道。发生阻塞是因为管道为空或管道已满(管道的大小当然是有限的)。

–凯尔·琼斯(Kyle Jones)
20/09/26在15:52



#3 楼

冒着击败一匹死马的危险,误解似乎是

    A | B


等同于

    A > temporary_file
    B < temporary_file
    rm temporary_file


但是,在Unix诞生之初,孩子们骑着恐龙上学时,
磁盘非常小,而且相当温和的命令通常会消耗文件系统中的所有可用空间。
如果B类似于
grep some_very_obscure_string,则
管道的最终输出可能比中间文件小得多。
因此,开发了管道,而不是“先运行A,然后用A的输出输入B进行运行”模型的简写,
而是B执行的一种方式与A同时进行
并消除了将中间文​​件存储在磁盘上的需求。

评论


这回答了为什么,因此得到我的投票。

– LAFK说恢复莫妮卡
18年1月3日在23:29

#4 楼

通常,您在bash下运行它。进程同时工作和启动,但由外壳程序并行运行。怎么可能?


如果不是管道中的最后一个命令,请在子项restsign stdin / stdout中创建带有一对套接字的未命名管道
fork
如果需要,则使用套接字(未重新分配管道stdin中的第一个进程,对于最后一个进程及其stdout,则重新分配套接字)
在子EXEC指定的命令中,该命令带有清除原始shell代码的参数,但保留所有由它们打开的套接字。子进程ID不会更改,因为这与子进程同时是同一个子进程,但在主外壳程序下是并行的,请转到步骤1。

系统不能保证exec的执行和指定速度如何命令启动。它独立于外壳,但独立于系统。这是因为:

ps auxww| grep ps | cat


一次显示grep和/或ps命令,然后接下来。这取决于内核使用系统exec函数真正启动进程的速度。

评论


并发执行意味着两个或多个进程在同一时间范围内执行,通常它们之间具有某种依赖性。并行执行意味着两个或多个进程同时执行(例如,同时在不同的CPU内核上执行)。并行性与问题无关,exec()的执行速度也不快,但是exec()的调用和管道中程序的执行是交错的。

–托马斯·尼曼(Thomas Nyman)
2013年9月6日上午10:25