问题描述
我有一个与用户交互的程序(行为类似于shell),并且我想使用Python子进程模块以交互方式运行它.这意味着,我希望可以写入标准输入并立即从标准输出中获取输出.我尝试了这里提供的许多解决方案,但是似乎没有一个可以满足我的需求.
I have a program that interacts with the user (acts like a shell), and I want to run it using the Python subprocess module interactively.That means, I want the possibility to write to standard input and immediately get the output from standard output. I tried many solutions offered here, but none of them seems to work for my needs.
我编写的代码基于 运行交互式在Python中执行命令 .
The code I've written is based on 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)
问题是队列保持为空,就像没有输出一样.仅当我将标准程序需要执行和终止的所有输入都写到标准输入中时,我才得到输出(这不是我想要的).例如,如果我做类似的事情:
The problem is that the queue remains empty, as if there is no output.Only if I write to standard input all the input that the program needs to execute and terminate, then I get the output (which is not what I want). For example, if I do something like:
p.stdin.write("1\n5\n")
errors = getOutput(errQueue)
output = getOutput(outQueue)
有没有办法做我想做的事?
Is there a way to do what I want to do?
该脚本将在Linux机器上运行.我更改了脚本,并删除了Universal_newlines = True +将bufsize设置为1,并在写入后立即刷新了标准输入.仍然没有任何输出.
The script will run on a Linux machine. I changed my script and deleted the universal_newlines=True + set the bufsize to 1 and flushed standard input immediately after write. Still I don't get any output.
第二次尝试:
我尝试了此解决方案,它对我有用:
I tried this solution and it works for me:
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()
推荐答案
在Linux上针对此问题的两种解决方案:
Two solutions for this issue on Linux:
第一个是使用文件将输出写入其中,并同时读取输出:
First one is to use a file to write the output to, and read from it simultaneously:
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()
第二,正如塞巴斯蒂安(J.F. Sebastian)提出的那样,是使用fnctl模块使p.stdout和p.stderr管道不阻塞:
Second, as J.F. Sebastian offered, is to make p.stdout and p.stderr pipes non-blocking using fnctl module:
import os
import fcntl
from subprocess import Popen, PIPE
def setNonBlocking(fd):
"""
Set the file description of the given file descriptor to non-blocking.
"""
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
flags = flags | os.O_NONBLOCK
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
p = Popen("./a.out", stdin = PIPE, stdout = PIPE, stderr = PIPE, bufsize = 1)
setNonBlocking(p.stdout)
setNonBlocking(p.stderr)
p.stdin.write("1\n")
while True:
try:
out1 = p.stdout.read()
except IOError:
continue
else:
break
out1 = p.stdout.read()
p.stdin.write("5\n")
while True:
try:
out2 = p.stdout.read()
except IOError:
continue
else:
break
这篇关于使用Python的交互式输入/输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!