我从来没有真正考虑过 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 …,这是抽签的运气(或外壳与内核的肠子调度微调深相结合的工作的细节问题)是否ps或grep首次启动时,在任何情况下,他们继续同时执行。
这通常用于允许第二个程序在第一个程序完成其操作之前处理来自第一个程序的数据。例如
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完成读取其输入文件之前停止处理。
如果您在某处读到管道程序按顺序运行,请远离本文档。管道程序并发运行并且始终具有。
Kyl*_*nes 52
命令运行的顺序实际上无关紧要,也不能保证。撇开pipe(), fork(),dup()和的神秘细节不谈execve(),外壳首先创建管道,即数据在进程之间流动的管道,然后创建将管道末端连接到它们的进程。运行的第一个进程可能会阻塞等待第二个进程的输入,或者阻塞等待第二个进程开始从管道读取数据。这些等待可以是任意长的并且无关紧要。无论进程以何种顺序运行,数据最终都会被传输并且一切正常。
Sco*_*ott 36
冒着打败死马的风险,误解似乎是
一个| 乙
相当于
A >临时文件
B <临时文件
rm临时文件
但是,在创建 Unix 并且孩子们骑着恐龙上学时,磁盘非常小,并且一个相当温和的命令消耗文件系统中的所有可用空间是很常见的。如果B是像
,管道的最终输出可以是多比中间文件更小。因此,管道的开发不是作为“先运行A,然后使用A输出的输入运行B ”模型的简写,而是作为一种与
中间文件并发执行并消除存储中间文件的需要的方式磁盘上。grep some_very_obscure_stringBA