kolurbo
kolurbo

Reputation: 538

Python subprocess package returns broken pipe

I am trying to do a very simple example of using subprocess package. The python script should open a new process and run read command. read command should receive input from stdin via PIPE. Every time when I try to use write() and flush() it says:

Traceback (most recent call last):
  File "recorder.py", line 68, in <module>
    p.stdin.flush()
BrokenPipeError: [Errno 32] Broken pipe

My python code looks like:

import subprocess
import time


p = subprocess.Popen(
    [
        "read",
    ],
    stdout=subprocess.PIPE,
    stdin=subprocess.PIPE,
    stderr=subprocess.STDOUT,
    shell=True,
    bufsize=1
)

for character in "This is the message!\n":
    p.stdin.write(character.encode("utf-8"))
    time.sleep(0.25)
    p.stdin.flush()

assert p.returncode == 0

Note: it's very important to send character after character (with sleeping timeout).

Upvotes: 1

Views: 2138

Answers (1)

Ondrej K.
Ondrej K.

Reputation: 9679

I actually could not replicate your result*, in my case your loop runs through and it'd fail on the assert as p has not finished yet and has no returncode (or rather its value is still None at that time). Inserting p.wait() after the loop and before the assert would force we only check for result after p has terminated.

Now for the exception you're seeing, it most likely indicates the pipe you're trying to perform flush() on is closed. Most likely due to the process having already terminated. Perhaps in your case at that point it already has a (non-zero) returncode too which could further help understand the problem?**


* On my system /bin/sh used by subprocess.Popen() with shell=True is actually bash. Running ["/bin/dash", "-c", "read"] which presumably happens to be shell called for /bin/sh on your system, I got broken pipe as well.


** Running dash like this seems to fail with:

/bin/dash: 1: read: arg count

And return 2.

Which sort of makes it more of a dash question: why calling /bin/dash -c "read" (from python) fails. It appears that dash read (unlike its bash counterpart) always expect at least one variable name to read into as an argument (replace read with read foo).


I guess this python question just became a lesson about assumptions and shell scripts portability. :)

Upvotes: 2

Related Questions