ver*_*min 23 python subprocess
我尝试完成的任务是流式传输ruby文件并打印出输出.(注意:我不想一次打印出所有内容)
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!")
Run Code Online (Sandbox Code Playgroud)
ruby_sleep.rb
puts "hello"
sleep 2
puts "goodbye!"
Run Code Online (Sandbox Code Playgroud)
问题
流文件工作正常.hello/goodbye输出以2秒延迟打印.正如脚本应该工作.问题是readline()最后会挂起而永不退出.我从未到过最后一个印刷品.
我知道有很多这样的问题,这里有一个stackoverflow但是没有它们让我解决问题.我不是那个整个子流程的东西,所以请给我一个更实际/具体的答案.
问候
编辑
修复意外的代码.(与实际错误无关)
jfs*_*jfs 28
我假设您使用了pty
由于Q中概述的原因:为什么不使用管道(popen())?(到目前为止所有其他答案都忽略了你的"注意:我不想一次打印出所有内容").
pty
只是如文档中所述的 Linux :
因为伪终端处理高度依赖于平台,所以只有Linux代码才能执行.(Linux代码应该可以在其他平台上运行,但尚未经过测试.)
目前还不清楚它在其他操作系统上的效果如何.
你可以尝试pexpect
:
import sys
import pexpect
pexpect.run("ruby ruby_sleep.rb", logfile=sys.stdout)
Run Code Online (Sandbox Code Playgroud)
或者stdbuf
在非交互模式下启用行缓冲:
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()
Run Code Online (Sandbox Code Playgroud)
或者使用pty
基于@Antti Haapala的答案的 stdlib :
#!/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!")
Run Code Online (Sandbox Code Playgroud)
所有三个代码示例都会立即打印"hello"(只要看到第一个EOL).
在这里留下旧的更复杂的代码示例,因为它可能在SO上的其他帖子中被引用和讨论
或者pty
根据@Antti Haapala的答案使用:
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!")
Run Code Online (Sandbox Code Playgroud)
不确定您的代码有什么问题,但以下内容似乎对我有用:
#!/usr/bin/python
from subprocess import Popen, PIPE
import threading
p = Popen('ls', stdout=PIPE)
class ReaderThread(threading.Thread):
def __init__(self, stream):
threading.Thread.__init__(self)
self.stream = stream
def run(self):
while True:
line = self.stream.readline()
if len(line) == 0:
break
print line,
reader = ReaderThread(p.stdout)
reader.start()
# Wait until subprocess is done
p.wait()
# Wait until we've processed all output
reader.join()
print "Done!"
Run Code Online (Sandbox Code Playgroud)
请注意,我没有安装 Ruby,因此无法检查您的实际问题。ls
不过,与 一起工作得很好。
归档时间: |
|
查看次数: |
24563 次 |
最近记录: |