2013-11-09 43 views
12

我有一個程序與用戶交互(就像一個shell),我想用交互式的python子進程模塊來運行它。 這意味着,我想要寫入stdin並立即從stdout獲得輸出的可能性。我嘗試了很多這裏提供的解決方案,但他們都沒有滿足我的需求。使用Python的交互式輸入/輸出

的代碼中,我根據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) 

有沒有辦法做我想做的事情?

編輯: 該腳本將在Linux機器上運行。 我改變了我的腳本,並刪除了universal_newlines = True +將bufsize設置爲1,並在wrtie之後立即刷新stdin。我仍然沒有輸出。

第二個嘗試: 我想這個解決方案,它爲我的作品:

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() 

回答

12

兩個方案來解決這個問題,在Linux上:

第一個是使用一個文件中寫入輸出並同時讀取它:

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() 

其次,作爲JF塞巴斯蒂安提供的,是讓p.stdout和p.stderr p Ipes非阻塞使用fnctl模塊:

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 
+0

我不完全明白你的意思。我最初想做的只是讀取部分輸出(一行) –

+0

我不理解你的例子。這行是什麼: p = Popen([sys.executable,「-u」,'-c' 'iner iter(input,「」):print(「a」* int(line)* 10 * * 6)'], stdin = PIPE,stdout = PIPE,bufsize = 1)是什麼意思? –

+0

你是對的,我編輯了我的第二個解決方案,因爲我用它。問題是,當我第一次嘗試解決方案時,我已經嘗試了python解釋器(我沒有寫腳本,只是手動測試過),所以它工作(由於人類響應時間慢)。 當我試圖編寫腳本時,我遇到了你提到的問題,所以我添加了while循環,直到輸入準備就緒。我實際上得到了整個輸出或者什麼也沒有(IOError異常),如果我上傳a.out源代碼(它是一個C程序)會有幫助嗎? –

相關問題