假设我有以下脚本:
test.sh
#!/bin/bash command1 #prints 5 lines command2 #prints 3 lines
我运行脚本 test.sh|head -n5
test.sh|head -n5
在这种情况下会发生什么?它会同时运行两个命令吗?还是会在command1之后停止?如果我用 -n1 调用该怎么办?
背景: 我可能会问一个非常基本的问题,但实际上我注意到了一些有趣的事情。我的脚本(不同的脚本)正在处理7,000个文件,每个文件产生1行输出。完全运行脚本需要7分钟,但是执行 head -n1会 立即提示我,因为脚本仅在处理了第一个文件后已终止
编辑: 以下是我的脚本
for i in $(ls filepath);do echo "$i" # issue here python mySript "$i" > "/home/user/output/""$i"".out" fi done
删除上面的 echo 可使脚本使用 head -n1 运行整整7分钟,但使用echo则仅打印第一行,然后退出。
这是一个相当有趣的问题!感谢您发布!
我假设这是head在处理了前几行后在退出时发生的,所以当它尝试下一次时,SIGPIPE信号会发送到运行该脚本的bashecho $x。我使用RedX的脚本来证明这一理论:
head
SIGPIPE
echo $x
#!/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它仅将两行写入屏幕和x.log。但是捕获SIGPIPE会改变这种行为…
t.sh|head -n 2
#!/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行。
stdout
man 7 signal
这也解释了为什么/bin/echo解决了这个问题。请参阅以下脚本:
/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尝试写入stdout时,它得到了SIGPIPE并被终止(作为默认行为),而不是bash运行脚本。