Python subprocess readlines() hangs
python, subprocess
Solution
I assume you use `pty` due to reasons outlined in Q: Why not just use a pipe (popen())? (all other answers so far ignore your "NOTE: I don't want to print out everything at once").
`pty` is Linux only as said in the docs:
Because pseudo-terminal handling is highly platform dependent, there is code to do it only for Linux. (The Linux code is supposed to work on other platforms, but hasn’t been tested yet.)
It is unclear how well it works on other OSes.
You could try `pexpect`:
import sys
import pexpect
pexpect.run("ruby ruby_sleep.rb", logfile=sys.stdout)
Or `stdbuf` to enable line-buffering in non-interactive mode:
from subprocess import Popen, PIPE, STDOUT
proc = Popen(['stdbuf', '-oL', 'ruby', 'ruby_sleep.rb'],
bufsize=1, stdout=PIPE, stderr=STDOUT, close_fds=True)
for line in iter(proc.stdout.readline, b''):
print line,
proc.stdout.close()
proc.wait()
Or using `pty` from stdlib based on @Antti Haapala's answer:
#!/usr/bin/env python
import errno
import os
import pty
from subprocess import Popen, STDOUT
master_fd, slave_fd = pty.openpty() # provide tty to enable
# line-buffering on ruby's side
proc = Popen(['ruby', 'ruby_sleep.rb'],
stdin=slave_fd, stdout=slave_fd, stderr=STDOUT, close_fds=True)
os.close(slave_fd)
try:
while 1:
try:
data = os.read(master_fd, 512)
except OSError as e:
if e.errno != errno.EIO:
raise
break # EIO means EOF on some systems
else:
if not data: # EOF
break
print('got ' + repr(data))
finally:
os.close(master_fd)
if proc.poll() is None:
proc.kill()
proc.wait()
print("This is reached!")
All three code examples print 'hello' immediately (as soon as the first EOL is seen).
leave the old more complicated code example here because it may be referenced and discussed in other posts on SO
Or using `pty` based on @Antti Haapala's answer:
import os
import pty
import select
from subprocess import Popen, STDOUT
master_fd, slave_fd = pty.openpty() # provide tty to enable
# line-buffering on ruby's side
proc = Popen(['ruby', 'ruby_sleep.rb'],
stdout=slave_fd, stderr=STDOUT, close_fds=True)
timeout = .04 # seconds
while 1:
ready, _, _ = select.select([master_fd], [], [], timeout)
if ready:
data = os.read(master_fd, 512)
if not data:
break
print("got " + repr(data))
elif proc.poll() is not None: # select timeout
assert not select.select([master_fd], [], [], 0)[0] # detect race condition
break # proc exited
os.close(slave_fd) # can't do it sooner: it leads to errno.EIO error
os.close(master_fd)
proc.wait()
print("This is reached!")
Problem
The task I try to accomplish is to stream a ruby file and print out the output. (NOTE: I don't want to print out everything at once) main.py ``` from subprocess import Popen, PIPE, STDOUT import pty import os file_path = '/Users/luciano/Desktop/ruby_sleep.rb' command = ' '.join(["ruby", file_path]) master, slave = pty.openpty() proc = Popen(command, bufsize=0, shell=True, stdout=slave, stderr=slave, close_fds=True) stdout = os.fdopen(master, 'r', 0) while proc.poll() is None: data = stdout.readline() if data != "": print(data) else: break print("This is never reached!") ``` ruby_sleep.rb ``` puts "hello" sleep 2 puts "goodbye!" ``` Problem Streaming the file works fine. The hello/goodbye output is printed with the 2 seconds delay. Exactly as the script should work. The problem is that readline() hangs in the end and never quits. I never reach the last print. I know there is a lot of questions like this here a stackoverflow but non of them made me solve the problem. I'm not that into the whole subprocess thing so please give me a more hands-on/concrete answer. Regards edit Fix unintended code. (nothing to do with the actual error)
Related problems
- Python subprocess .check_call vs .check_output
- Run command and get its stdout, stderr separately in near real time like in a terminal
- Using subprocess with select and pty hangs when capturing output
- Python 3.4.3 subprocess.Popen get output of command without piping?
- Capture output as a tty in python
- python popen.stdout.readline() hangs