Answers:
这是由于实施中的选择。
在Solaris上与一起运行相同的脚本ksh93
会产生不同的行为:
$ while /usr/bin/true ; do echo "ok" | cat ; done | exit 1
cat: write error [Broken pipe]
触发该问题的是内部管道,如果没有内部管道,则无论shell / OS是什么,循环都会退出:
$ while /usr/bin/true ; do echo "ok" ; done | exit 1
$
cat
在bash下获取SIGPIPE信号,但是shell无论如何都在循环。
Process 5659 suspended
[pid 28801] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
[pid 28801] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28801 detached
Process 28800 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Process 28802 attached
Process 28803 attached
[pid 28803] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
Process 5659 suspended
[pid 28803] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28803 detached
Process 28802 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Process 28804 attached
Process 28805 attached (waiting for parent)
Process 28805 resumed (parent 5659 ready)
Process 5659 suspended
[pid 28805] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
[pid 28805] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28805 detached
Process 28804 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Bash文档指出:
在返回值之前,shell 等待管道中的所有命令终止。
Ksh文档指出:
除最后一条命令外,每个命令都作为单独的进程运行;Shell 等待最后一条命令终止。
POSIX指出:
如果管道不在后台(请参见异步列表),则外壳程序应等待管道中指定的最后一条命令完成,也可以等待所有命令完成。
echo
函数忽略了SIGPIPE。您还可以通过使用env echo
代替重现问题echo
(强制使用实际的echo
二进制文件)。(还要比较{ echo hi; echo $? >&2; } | exit 1
和的输出{ env echo hi; echo $? >&2; } | exit 1
。)
这个问题困扰了我多年。感谢jilliagre朝着正确的方向前进。
在我的linux盒子上稍微重申一下这个问题,这退出了预期:
while true ; do echo "ok"; done | head
但是,如果我添加了一个管道,它并没有退出预期:
while true ; do echo "ok" | cat; done | head
这使我沮丧了很多年。通过考虑jilliagre编写的答案,我得出了一个奇妙的解决方法:
while true ; do echo "ok" | cat || exit; done | head
QED ...
好吧,不完全是。这里有些复杂:
i=0
while true; do
i=`expr $i + 1`
echo "$i" | grep '0$' || exit
done | head
这行不通。我添加了,|| exit
因此它知道如何提前终止,但是第一个echo
不匹配,grep
因此循环立即退出。在这种情况下,您实际上对的退出状态不感兴趣grep
。我的解决方法是添加另一个cat
。因此,这是一个称为“ tens”的人为脚本:
#!/bin/bash
i=0
while true; do
i=`expr $i + 1`
echo "$i" | grep '0$' | cat || exit
done
当以方式运行时,这会正确终止tens | head
。感谢上帝。