这是一个相当有趣的问题!感谢您发布!
我假设这是
head在处理了前几行后在退出时发生的,所以当它尝试下一次时,
SIGPIPE信号会发送到运行该脚本的bash
echo $x。我使用RedX的脚本来证明这一理论:
#!/usr/bin/bashrm x.logfor((x=0;x<5;++x)); do echo $x echo $x>>x.logdone
如您所描述的那样,这有效!使用
t.sh|head -n 2它仅将两行写入屏幕和x.log。但是捕获SIGPIPE会改变这种行为…
#!/usr/bin/bashtrap "echo SIGPIPE>&2" PIPErm x.logfor((x=0;x<5;++x)); do echo $x echo $x>>x.logdone
输出:
$ ./t.sh |head -n 201./t.sh: line 5: echo: write error: Broken pipeSIGPIPE./t.sh: line 5: echo: write error: Broken pipeSIGPIPE./t.sh: line 5: echo: write error: Broken pipeSIGPIPE
当
stdout管道另一端关闭时,由于已经关闭而发生写入错误。尝试写入关闭的管道都会导致SIGPIPE信号,该信号默认会终止程序(请参阅参考资料
man7 signal)。x.log现在包含5行。
这也解释了为什么
/bin/echo解决了这个问题。请参阅以下脚本:
rm x.logfor((x=0;x<5;++x)); do /bin/echo $x echo "Ret: $?">&2 echo $x>>x.logdone
输出:
$ ./t.sh |head -n 20Ret: 01Ret: 0Ret: 141Ret: 141Ret: 141
十进制141
=十六进制8D。十六进制80表示已接收到信号,十六进制0D用于SIGPIPE。因此,当
/bin/echo尝试写入stdout时,它得到了SIGPIPE并被终止(作为默认行为),而不是bash运行脚本。



