小编典典

Bash:bash脚本的头尾行为

linux

假设我有以下脚本:

test.sh

#!/bin/bash
command1  #prints 5 lines
command2  #prints 3 lines

我运行脚本 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则仅打印第一行,然后退出。


阅读 353

收藏
2020-06-07

共1个答案

小编典典

这是一个相当有趣的问题!感谢您发布!

我假设这是head在处理了前几行后在退出时发生的,所以当它尝试下一次时,SIGPIPE信号会发送到运行该脚本的bashecho $x。我使用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它仅将两行写入屏幕和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尝试写入stdout时,它得到了SIGPIPE并被终止(作为默认行为),而不是bash运行脚本。

2020-06-07