从管道中的BASH无限循环退出

从管道中的BASH无限循环退出,bash,shell,unix,Bash,Shell,Unix,我遇到了BASH无限循环的一个有点奇怪的行为,它的输出通过管道传输到另一个进程。即,我运行以下两个命令: (while true; do echo xxx; done) | head -n 1 (while true; do date; done) | head -n 1 第一个会立即退出,而第二个不会(我认为它会永远运行而不会被杀死)。我还尝试了隐式无限循环: yes | head -n 1 而且它本身也存在。在每种情况下,屏幕上都会立即打印出相应的输出行。我只是好奇是什么决定了这样一个命

我遇到了BASH无限循环的一个有点奇怪的行为,它的输出通过管道传输到另一个进程。即,我运行以下两个命令:

(while true; do echo xxx; done) | head -n 1
(while true; do date; done) | head -n 1
第一个会立即退出,而第二个不会(我认为它会永远运行而不会被杀死)。我还尝试了隐式无限循环:

yes | head -n 1

而且它本身也存在。在每种情况下,屏幕上都会立即打印出相应的输出行。我只是好奇是什么决定了这样一个命令是否会结束。

head
退出时,括号内表达式的标准输出关闭。如果使用外部命令,如
date
,循环将挂起。如果使用bash的内部命令,如
echo
,则循环退出。为了证明,使用

(while true; do /bin/echo xxx; done) | head -n 1
它会挂起来的。如果你使用

(while true; do date; echo $? 1>&2; sleep 1; done) | head -n 1
您将看到,在第二轮中,
date
命令返回一个错误退出代码,即除零之外的其他值。Bash显然没有内部命令出现问题那么严重。我想知道这是不是有意的,或者更确切地说是bash中的一个bug

要确保退出循环,这似乎有效:

(set -e; while true; do date ; done) | head -n 1

谢谢,这是有意义的。唯一退出的进程是当
head
退出时尝试写入遗留的关闭文件句柄的进程。当外部程序
date
成为“牺牲品”时,
bash
shell将继续,不断生成
date
进程,这些进程尝试写入和接收
SIGPIPE
。内置的是
bash
shell本身接收
SIGPIPE
,因此它退出,终止管道。
set-e
起作用,因为当
date
第一次尝试写入关闭的文件句柄时,它以非零状态退出,这将导致运行while循环的
bash
shell也根据
-e
选项退出;
while
循环本身就是一个完整的命令,它可以位于管道的左侧。