2013-11-09 13 views
12

私はユーザーとやり取りする(シェルのような)プログラムを持っており、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をフラッシュしました。それでも私は出力がありません。

2回目の試行: 私は、このソリューションを試してみましたが、それが私の作品:

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

2つの溶液を、この問題のために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を作ることですfnctlモジュールを使用して非ブロッキングipes:

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

私はあなたが意味するものを正確に理解していません。私が最初にやったかったのは、部分出力(1行)だけを読むことです。 –

+0

私はあなたの例を理解しませんでした。p = Popen([sys.executable、 "-u"、 '-c''for iter(input、 "):print(" a "* int(line)* 10 * * 6) ']、 stdin = PIPE、stdout = PIPE、bufsize = 1)mean? –

+0

あなたはそうです、私はそれを使ったときに私の2番目の解決策を編集しました。問題は、私が最初に解決策を試したときに、Pythonインタプリタで試したことです(私はスクリプトを書かず、手動でテストしただけです)ので、(人間の応答時間が遅いため)機能しました。 スクリプトを書き込もうとしましたが、私が指摘した問題が発生したため、入力が準備されるまでwhileループを追加しました。私は実際に出力全体を取得するか、何もしません(IOError例外)、a.outソースコード(Cプログラム)をアップロードすると役立ちますか? –

関連する問題