1

I am running a subprocess using 'Popen'. I need to block till this subprocess finishes and then read its output.

p = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, encoding="utf-8")
p.communicate():
output = p.stdout.readline()
print(output)

I get an error that

ValueError: I/O operation on closed file.

How can I read the output after the subprocess finishes, I do not want to use poll() though as the subprocess takes time and I would need to wait for its completion anyway.

4
  • 2
    p.communicate() returns the output. Commented Aug 2, 2018 at 18:29
  • Any particular reason you're not using subprocess.run() or the legacy subprocess.check_output()? You should avoid Popen if you can precisely because it's tricky to get right. Commented Aug 2, 2018 at 18:29
  • @jasonharper, p.communicate() returns bound method Popen.communicate of <subprocess.Popen object at 0x105e84e10, not the output of the subprocess code Commented Aug 2, 2018 at 18:34
  • output, error = p.communicate() should work, that output looks like you are just printing p.communicate (without the parentheses). Commented Aug 2, 2018 at 18:36

3 Answers 3

2

This should work:

p = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, encoding="utf-8")
output, error = p.communicate()

print(output)
if error:
    print('error:', error, file=sys.stderr)

However, subprocess.run() is preferred these days:

p = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

print("output:", p.stdout)

if proc.stderr:
    print("error:", p.stderr, file=sys.stderr)
Sign up to request clarification or add additional context in comments.

Comments

0

Use subprocess.check_output. It returns the output of the command.

Comments

0

actually when I wanted to run python3 -c "import time;time.sleep(3);print(1)" with subprocess.run or subprocess.Popen I faced that problem of not collecting outputs and returning before child process ended. The only feasible solution was/is for me asyncio code (for 3.6) below but for newer version will be pretty similar:

class ShellCommand(Command):
  OK = 0
  ENCODING = 'utf-8'

  def run(self, args: List[str]) -> str:
    cmd = ' '.join(args)
    logging.info('executing %s', cmd)
    async def _run(cmd: str, future: asyncio.Future):
        proc = await asyncio.create_subprocess_shell(
            cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.STDOUT)
        stdout, stderr = await proc.communicate()
        if proc.returncode != type(self).OK:
          raise ValueError(f'Return code: {proc.returncode}', f'Message: {stderr.decode(type(self).ENCODING)}')
        future.set_result(stdout.decode(type(self).ENCODING))
    asyncio.set_event_loop(asyncio.new_event_loop())
    loop = asyncio.get_event_loop()
    future = asyncio.Future()
    asyncio.ensure_future(_run(cmd, future), loop=loop)
    loop.run_until_complete(future)
    loop.close()
    return future.result()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.