Linux 为什么这个shell管道会退出?

Linux 为什么这个shell管道会退出?,linux,bash,unix,pipe,Linux,Bash,Unix,Pipe,我有一个随机生成10个字符密码的shell管道: cat /dev/urandom | base64 | head -c 10 我的问题是,cat/dev/uradom | base64是一个无限的输出流,它本身不会退出。但是为什么追加head-c10会使整个管道退出呢?我假设cat,base64和head是三个独立的进程,那么head如何使cat进程退出呢 head读取所需金额后关闭输入文件。当管道从一侧关闭时,另一侧会出现写入错误;这会导致base64关闭,进而导致cat关闭。管道通过将一

我有一个随机生成10个字符密码的shell管道:

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

我的问题是,
cat/dev/uradom | base64
是一个无限的输出流,它本身不会退出。但是为什么追加
head-c10
会使整个管道退出呢?我假设
cat
base64
head
是三个独立的进程,那么
head
如何使
cat
进程退出呢

head
读取所需金额后关闭输入文件。当管道从一侧关闭时,另一侧会出现写入错误;这会导致
base64
关闭,进而导致
cat
关闭。

管道通过将一个过程A的输出连接到B的输入来工作。当

  • A关闭其输出。B将获得EOF
  • B关闭其输入。当尝试写入下一个字节时,将出现输出不再可用的错误

由于这两种情况非常常见,因此处理被移动到C标准库中。

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

谢谢,但是“处理已移动到C标准库”是什么意思?A和B是否由外壳端接,而不是检测到输入/输出关闭并自行停止?当B关闭其管道一侧时,A将收到信号。标准库c.lib的I/O例程中的代码(
fprintf()
open()
read()
,…)处理信号,函数调用将返回errno eppe=“break pipe”。@AaronDigulla,我不同意。我不知道有哪个C库安装了SIGPIPE处理程序,我的实验也没有表明这一点。事实上,SIGPIPE已经交付,这会导致任何未安装处理程序的程序(即99%的程序)退出。正确,Rob,这是SIGPIPE。谢谢你能想出一个答案吗?我会接受的。目前,这两个答案并不完全正确。@Robᵩ: 我的意思是,您在控制台中看不到“断管”错误,因此必须有人处理此信号。可能值得一提的是,
head
获取任何输入的唯一原因是,
base64
在获得一定量的输入后写入输出,即当其缓冲区已满时。如果它一直读到EOF,它将永远读下去,
head
将永远不会有裂缝。因此类似的管道,如
cat/dev/uradom | sum | head-c10
,将表现不同,因为
sum
等待EOF。Rob的评论非常相关。如果进程继承SIGPIPE处理程序或忽略SIGPIPE(例如,如果它在较旧的python解释器子进程模块下运行),并且没有检查写入错误,那么它将不会终止。写错误和接收SIGPIPE之间有很大的区别,忽略这两个问题的程序很容易无限期地运行。@williampersell:进程不能继承SIGPIPE处理程序。它可以继承SIG_IGN non处理程序,但当进程使用
exec()
替换自身时,任何信号处理程序都会重置为默认值。不难看出原因:对于新进程来说,指向旧进程中函数的指针几乎肯定不是一个好的选择。但您是对的,一个忽略写入错误并同时忽略SIGPIPE的进程将继续工作太长时间。