Bash:用bash脚本进行头部和尾部行为

假设我有以下脚本:

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 ,并解决了这个问题。 我希望他能更多地解释这种行为。