Suppose I have following script:-
command1 #prints 5 lines
command2 #prints 3 lines
for i in $(ls filepath);do
echo "$i" # issue here
python mySript "$i" > "/home/user/output/""$i"".out"
This is a fairly interesting issue! Thanks for posting it!
I assumed that this happens as
head exits after processing the first few lines, so
SIGPIPE signal is sent to the bash running the script when it tries to
echo $x next time. I used RedX's script to prove this theory:
#!/usr/bin/bash rm x.log for((x=0;x<5;++x)); do echo $x echo $x>>x.log done
This works, as You described! Using
t.sh|head -n 2 it writes only 2 lines to the screen and to x.log. But trapping SIGPIPE this behavior changes...
#!/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
The write error occurs as
stdout is already closed as the other end of the pipe is closed. And any attempt to write to the closed pipe causes a SIGPIPE signal, which terminates the program by default (see
man 7 signal). The x.log now contains 5 lines.
This also explains why
/bin/echo solved the problem. See the following script:
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
Decimal 141 = hex 8D. Hex 80 means a signal was received, hex 0D is for SIGPIPE. So when
/bin/echo tried to write to stdout it got a SIGPIPE and it was terminated (as default behavior) instead of the bash running the script.