Script works differently when ran from the terminal and ran from Python
<p>I have a short bash script <code>foo.sh</code></p>

<pre><code>#!/bin/bash

cat /dev/urandom | tr -dc 'a-z1-9' | fold -w 4 | head -n 1
</code></pre>

<p>When I run it directly from the shell, it runs fine, exiting when it is done</p>

<pre><code>$ ./foo.sh 
m1un
$
</code></pre>

<p>but when I run it from Python</p>

<pre><code>$ python -c "import subprocess; subprocess.call(['./foo.sh'])"
ygs9
</code></pre>

<p>it outputs the line but then just hangs forever. What is causing this discrepancy? </p>

<p>Adding the <code>trap -p</code> command to the bash script, stopping the hung python process and running <code>ps</code> shows what's going on:</p>

<pre><code>$ cat foo.sh
#!/bin/bash

trap -p
cat /dev/urandom | tr -dc 'a-z1-9' | fold -w 4 | head -n 1

$ python -c "import subprocess; subprocess.call(['./foo.sh'])"
trap -- '' SIGPIPE
trap -- '' SIGXFSZ
ko5o

^Z
[1]+  Stopped     python -c "import subprocess; subprocess.call(['./foo.sh'])"
$ ps -H -o comm
COMMAND
bash
  python
    foo.sh
      cat
      tr
      fold
  ps
</code></pre>

<p>Thus, <code>subprocess.call()</code> executes the command with the <code>SIGPIPE</code> signal masked. When <code>head</code> does its job and exits, the remaining processes do not receive the broken pipe signal and do not terminate.</p>

<p>Having the explanation of the problem at hand, it was easy to find the bug in the python bugtracker, which turned out to be <a href="https://bugs.python.org/issue1652">issue#1652</a>.</p>

python bash subprocess pipeline