假设我有以下脚本:
test.sh
#!/bin/bash command1 #prints 5 lines command2 #prints 3 lines
我用test.sh|head -n5运行脚本
在这种情况下会发生什么? 它会运行这两个命令吗? 或者它会在command1之后停止? 如果我用-n1打电话怎么办?
背景:我可能会提出一个非常基本的问题,但我真的注意到了一些有趣的事情。 我的脚本(不同的)正在处理7000个文件,每个文件产生1行输出。 完全运行脚本需要7分钟,但是执行头-n1会立即给出提示,类似脚本在处理第一个文件后终止
编辑:以下是我的脚本
for i in $(ls filepath);do echo "$i" # issue here python mySript "$i" > "/home/user/output/""$i"".out" fi done
删除上面的echo使脚本运行整个7分钟头-n1 ,但与回声只是打印第一行然后退出。
这是一个相当有趣的问题! 感谢张贴!
我认为这是在处理头几行后退出的,所以SIGPIPE信号会在下次尝试echo $x时发送到运行脚本的bash 。 我用RedX的脚本来证明这个理论:
#!/usr/bin/bash rm x.log for((x=0;x<5;++x)); do echo $x echo $x>>x.log done
正如你所描述的,这个工作正常 使用t.sh|head -n 2它只写2行到屏幕和x.log。 但是陷阱SIGPIPE这个行为改变…
#!/usr/bin/bash trap "echo SIGPIPE>&2" PIPE rm x.log for((x=0;x<5;++x)); do echo $x echo $x>>x.log done
输出:
$ ./t.sh |head -n 2 0 1 ./t.sh: line 5: echo: write error: Broken pipe SIGPIPE ./t.sh: line 5: echo: write error: Broken pipe SIGPIPE ./t.sh: line 5: echo: write error: Broken pipe SIGPIPE
由于管道的另一端关闭, stdout已经关闭,因此发生写入错误。 任何试图写入闭合管道的信号都会产生一个SIGPIPE信号,默认终止程序(见man 7 signal )。 x.log现在包含5行。
这也解释了为什么/bin/echo解决了这个问题。 请参阅以下脚本:
rm x.log for((x=0;x<5;++x)); do /bin/echo $x echo "Ret: $?">&2 echo $x>>x.log done
输出:
$ ./t.sh |head -n 2 0 Ret: 0 1 Ret: 0 Ret: 141 Ret: 141 Ret: 141
十进制141 =十六进制8D。 十六进制80表示已收到信号,十六进制0D表示SIGPIPE。 所以当/bin/echo试图写入标准输出时,它得到了一个SIGPIPE,并被终止(作为默认行为),而不是运行脚本的bash 。
很好的发现。 根据我的测试,就像你说的那样。 例如,我有这个脚本,只是吃cpu,让我们发现它在top :
for i in `seq 10` do echo $i x=`seq 10000000` done
用head -n1脚本,我们看到在第一行之后返回的命令。 这是head行为:它完成了它的工作,所以它可以停止并将控制权交给你。
输入脚本应该继续运行,但看看会发生什么: head返回时,它的pid不再存在。 所以当linux试图将脚本的输出发送到head进程时,它没有找到进程,所以脚本崩溃并停止。
让我们用一个python脚本来测试它:
for i in xrange(10): print i range(10000000)
当它运行和管道到头你有这样的:
$ python -u test.py | head -n1 0 Traceback (most recent call last): File "test.py", line 2, in <module> print i IOError: [Errno 32] Broken pipe
-u选项告诉python自动刷新stdin和stdout,就像bash所做的那样。 所以你看到程序实际上停止了一个错误。
这更多的是一个评论,然后是一个答案,但它太大了评论。
我试过下面的脚本:
#!/usr/bin/env bash rm -f "test_head.log" echo "1 line" echo "1 line" >> "test_head.log" echo "2 line" echo "2 line" >> "test_head.log" echo "3 line" echo "3 line" >> "test_head.log" echo "4 line" echo "4 line" >> "test_head.log" echo "5 line" echo "5 line" >> "test_head.log" echo "6 line" echo "6 line" >> "test_head.log" echo "7 line" echo "7 line" >> "test_head.log" echo "8 line" echo "8 line" >> "test_head.log"
然后我跑了脚本:
./test_head.sh | 头-n1
猫的输出(令我惊讶):
1行
我不知道发生了什么事。
在阅读@ymonad评论后,我试了一下,并用/bin/echo替换echo ,并解决了这个问题。 我希望他能更多地解释这种行为。