我有一个与用户交互的程序(就像一个shell),我想以交互方式使用python子进程模块运行它 . 这意味着,我希望有可能写入stdin并立即从stdout获取输出 . 我在这里尝试了许多解决方案,但它们似乎都不能满足我的需求 .
我写的代码基于Running an interactive command from within python
import Queue
import threading
import subprocess
def enqueue_output(out, queue):
for line in iter(out.readline, b''):
queue.put(line)
out.close()
def getOutput(outQueue):
outStr = ''
try:
while True: #Adds output from the Queue until it is empty
outStr+=outQueue.get_nowait()
except Queue.Empty:
return outStr
p = subprocess.Popen("./a.out", stdin=subprocess.PIPE, stout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 1)
#p = subprocess.Popen("./a.out", stdin=subprocess.PIPE, stout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, universal_newlines=True)
outQueue = Queue()
errQueue = Queue()
outThread = Thread(target=enqueue_output, args=(p.stdout, outQueue))
errThread = Thread(target=enqueue_output, args=(p.stderr, errQueue))
outThread.daemon = True
errThread.daemon = True
outThread.start()
errThread.start()
p.stdin.write("1\n")
p.stdin.flush()
errors = getOutput(errQueue)
output = getOutput(outQueue)
p.stdin.write("5\n")
p.stdin.flush()
erros = getOutput(errQueue)
output = getOutput(outQueue)
问题是队列保持为空,就好像没有输出一样 . 只有当我向stdin写入程序需要执行和终止的所有输入时,我才得到输出(这不是我想要的) . 例如,如果我做了类似的事情:
p.stdin.write("1\n5\n")
errors = getOutput(errQueue)
output = getOutput(outQueue)
有什么办法可以做我想做的事吗?
EDIT: 该脚本将在Linux机器上运行 . 我更改了我的脚本并删除了universal_newlines = True将bufsize设置为1并在wrtie之后立即刷新stdin . 我仍然没有输出 .
Second try: 我试过这个解决方案,它对我有用:
from subprocess import Popen, PIPE
fw = open("tmpout", "wb")
fr = open("tmpout", "r")
p = Popen("./a.out", stdin = PIPE, stdout = fw, stderr = fw, bufsize = 1)
p.stdin.write("1\n")
out = fr.read()
p.stdin.write("5\n")
out = fr.read()
fw.close()
fr.close()
3 回答
Linux上针对此问题的两种解决方案:
第一个是使用文件将输出写入,并同时从中读取:
其次,正如J.F.Sebastian所提出的那样,是使用fnctl模块使p.stdout和p.stder管道无阻塞:
目前的答案都不适合我 . 最后,我有这个工作:
使用此
dummy.py
脚本进行测试:需要注意的是:输入/输出始终使用换行符,每次写入后刷新子级的stdin,并使用子级stdout中的
readline()
(函数中管理的所有内容) .这是一个非常简单的解决方案,在我看来(不是我的,我在这里找到了它:https://eli.thegreenplace.net/2017/interacting-with-a-long-running-child-process-in-python/) . 我使用的是Python 3.6 .
这是一个交互式shell . 你必须在一个单独的线程上运行read(),否则它将阻止write()