2

I try simple code using subprocess on python, while calling process.stdout.readline() it will hang on it. How to solve this problem? While trying fcntl for nonblock in the output I got blank output.

my source code:

from subprocess import Popen,PIPE 
import fcntl
import os

proc = Popen(['./test'],stdin=PIPE,stdout=PIPE) 

fcntl.fcntl(proc.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)

print "Started!"

print proc.stdout.readline()

proc.stdin.write('5\n')
proc.stdin.flush()

print proc.stdout.readline()

proc.stdin.write('5\n')
proc.stdin.flush()


print proc.stdout.readline()
proc.stdout.close()
proc.stdin.close()

The output should be like this:

First number: 5
Second number: 5
Answer: 10
fredtantini
  • 15,966
  • 8
  • 49
  • 55
Alihuseyn
  • 148
  • 1
  • 9

2 Answers2

0

Your desired output suggests that there is no newline after First number: and therefore the blocking proc.stdout.readline() call (before proc.stdin.write('5\n') line) hangs and non-blocking variant returns nothing (empty bytestring) -- there is no newline/EOF to return yet.

To fix it, you could stop reading at the end of the prompt (at the colon ':'). See subprocess readline hangs waiting for EOF

Even if there were a newline after the prompt; readline() may hang due to buffering issues. See Python C program subprocess hangs at "for line in iter"

For example, if test is equivalent to:

#!/usr/bin/env python3
a = int(input('First number: '))
b = int(input('Second number: '))
print('Answer:', a + b)

then to get the answer, you could use pexpect module:

#!/usr/bin/env python
import pexpect # $ pip install pexpect

def print_result(locals):
    result = int(locals['child'].after.rpartition(b' ')[2])
    print(result)

pexpect.run('./test', events={'First number': '5\n', 'Second number': '5\n',
                              r'Answer:\s*\d+': print_result})

If you want to see both input and output; you could set logfile=sys.stdout parameter.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
0

I meet a similar issue; and fix it by adding flush() before readline.

               proc.stdout.flush()
               proc.stdout.readline()

Now, I can see the output right away; looks flush() put EOF there; then readline is ready to go.