2012-04-05 48 views
17

这是随机生成10个字符的密码一个管道命令:这个管道为什么终止?

cat /dev/urandom | base64 | head -c 10 

我的问题是cat /dev/urandom | base64是一个无限的输出流,这将无法自动停止。但为什么追加head -c 10使整个管道终止?我假设cat,base64head是3个分离过程,head怎么能终止cat

回答

11

base64输出10个字节后,head获得足够的输入和退出。当前者尝试输出更多字节时,它将收到SIGPIPE signal,因此也会退出。出于同样的原因,cat将依次退出。

23

head在读取所需数量后关闭输入文件。当管道从一侧关闭时,另一侧出现写错误;这导致base64关闭,这又导致cat关闭。

+7

可能值得一提的是,'head'完全可以得到任何输入的是'base64'在输入达到一定数量后写入输出,也就是缓冲区满时。如果要阅读直到EOF,它将永远阅读,而“头”永远不会有任何裂缝。所以有一个类似的管道,比如'cat/dev/urandom |总和| head -c 10'会表现不同,因为'sum'等待EOF。 – 2012-04-05 16:23:32

+3

s /得到写入错误/收到SIGPIPE/ – 2012-04-05 18:38:41

+1

Rob的评论*非常相关。如果进程继承SIGPIPE处理程序或忽略SIGPIPE(例如,如果它在较早的python解释程序子进程模块下运行)并且不检查写入错误,则它不会终止。写入错误和接收SIGPIPE之间存在巨大的差异,忽略这两个问题的程序可能会无限期地运行。 – 2012-04-05 19:55:13

4

管道的工作方式是连接一个进程A的输出到B的输入端的连接可以被打破,当

  • A关闭它的输出。 B会得到EOF。
  • B关闭输入。 A会尝试写入下一个字节时出现输出不再可用的错误。

由于这两种情况如此常见,所以处理已移到C标准库中。

+0

谢谢,但“处理已移到C标准库”是什么意思? A和B是通过shell来终止的,而不是它们检测到输入/输出的关闭并自行停止? – Dagang 2012-04-05 15:31:44

+0

当B关闭其管道侧时,A将收到信号。标准库c.lib('fprintf()','open()','read()',...)的I/O例程中的代码处理信号,函数调用将返回errno EPIPE =“损坏的管道”。 – 2012-04-05 15:36:53

+1

@AaronDigulla,我不同意。我不知道任何安装了SIGPIPE处理程序的C库,我的实验也没有提示它。事实上,SIGPIPE交付后会导致任何未安装处理程序的程序(即所有程序的99%)退出。 – 2012-04-05 18:57:56