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

Man*_*odi 22 linux bash

假设我有以下脚本: -

test.sh

#!/bin/bash
command1  #prints 5 lines
command2  #prints 3 lines
Run Code Online (Sandbox Code Playgroud)

我运行脚本 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
Run Code Online (Sandbox Code Playgroud)

删除上面的回声使脚本能够使用head -n1运行整整7分钟,但是使用echo它只打印第一行然后退出.

Tru*_*ueY 17

这是一个相当有趣的问题!谢谢发帖!

我假设head在处理前几行后会出现这种情况,因此在下次尝试时会向运行脚本SIGPIPE发送信号echo $x.我使用RedX的脚本来证明这个理论:

#!/usr/bin/bash
rm x.log
for((x=0;x<5;++x)); do
    echo $x
    echo $x>>x.log
done
Run Code Online (Sandbox Code Playgroud)

这就像你描述的那样有用!使用t.sh|head -n 2它只会向屏幕和x.log写入2行.但陷阱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
Run Code Online (Sandbox Code Playgroud)

输出:

$ ./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
Run Code Online (Sandbox Code Playgroud)

由于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
Run Code Online (Sandbox Code Playgroud)

输出:

$ ./t.sh |head -n 2
0
Ret: 0
1
Ret: 0
Ret: 141
Ret: 141
Ret: 141
Run Code Online (Sandbox Code Playgroud)

十进制141 =十六进制8D.十六进制80表示接收到信号,十六进制0D表示SIGPIPE.因此,当/bin/echo尝试写入stdout时,它获得了一个SIGPIPE并且它被终止(作为默认行为)而不是运行脚本的.


enr*_*cis 8

很好的发现.根据我的测试,它就像你说的那样.例如,我有这个脚本只是吃cpu,让我们发现它top:

for i in `seq 10`
  do echo $i
  x=`seq 10000000`
done
Run Code Online (Sandbox Code Playgroud)

head -n1我们看到在第一行之后返回的命令管道脚本.这是head行为:它完成了它的工作,因此它可以停止并将控制返回给你.

输入脚本应该继续运行,但看看会发生什么:当head返回时,它的pid不再存在.因此,当linux尝试将脚本的输出发送到head进程时,它找不到进程,因此脚本崩溃并停止.

让我们用python脚本尝试一下:

for i in xrange(10):
    print i
    range(10000000)
Run Code Online (Sandbox Code Playgroud)

当它运行并且管道到头时你有这个:

$ 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
Run Code Online (Sandbox Code Playgroud)

-u选项告诉python自动刷新stdin和stdout,就像bash那样.所以你看到程序实际上因错误而停止.

  • @MangatRai 实际上我做了相反的事情,我想:bash?不,让我们用 python 写这个,然后错误就弹出了:)但是下次我在 bash 遇到奇怪的问题时我会再次使用 python! (2认同)