2013-10-02 33 views
1

我試圖捕捉從子進程的輸出,當子進程要求用戶輸入,在字符串中包含用戶輸入一個字符串,但我可以」不要讓stdout工作。獲取從程序輸出與用戶輸入該程序需要

我使用while循環標準輸出輸出字符串,但我不知道如何讀的字符串後終止。

我試着用subprocess.check_output,但我不能看到用戶輸入的提示。

import subprocess 
import sys 
child = subprocess.Popen(["java","findTheAverage"], stdout = subprocess.PIPE, stdin = subprocess.PIPE) 
string = u"" 

while True: 
    line = str(child.stdout.read(1)) 
    if line != '': 
     string += line[2] 
     print(string) 
    else: 
     break 

print(string) 
for line in sys.stdin: 
    print(line) 
    child.stdin.write(bytes(line, 'utf-8')) 

編輯:

的幫助和代碼ALFE後我現在有一個字符串,充分利用子程序輸出創建,並輸入到該程序的用戶,但其對混亂。

的字符串出現先得到輸出的第一個字母,然後在用戶輸入時,輸出的其餘部分。串混混的

實施例:

U2 
3ser! please enter a double:U 
4ser! please enter another double: U 
5ser! please enter one final double: Your numbers were: 
a = 2.0 
b = 3.0 
c = 4.0 
average = 3.0 

意味着是:

User! please enter a double:2 
User! please enter another double: 3 
User! please enter one final double: 4 
Your numbers were: 
a = 2.0 
b = 3.0 
c = 4.0 
average = 3.0 

使用代碼:

import subprocess 
import sys 
import signal 
import select 


def signal_handler(signum, frame): 
    raise Exception("Timed out!") 


child = subprocess.Popen(["java","findTheAverage"], universal_newlines = True, stdout = subprocess.PIPE, stdin = subprocess.PIPE) 
string = u"" 
stringbuf = "" 

while True: 
    print(child.poll()) 
    if child.poll() != None and not stringbuf: 
    break 
    signal.signal(signal.SIGALRM, signal_handler) 
    signal.alarm(1) 
    try: 
    r, w, e = select.select([ child.stdout, sys.stdin ], [], []) 
    if child.stdout in r: 
     stringbuf = child.stdout.read(1) 
     string += stringbuf 
     print(stringbuf) 
    except: 
    print(string) 
    print(stringbuf) 
    if sys.stdin in r: 
    typed = sys.stdin.read(1) 
    child.stdin.write(typed) 
    string += typed 

FINAL編輯:

好吧,我打得四處它,得到它,此代碼的工作:

import subprocess 
import sys 
import select 
import fcntl 
import os 

# the string that we will return filled with tasty program output and user input # 
string = "" 

# the subprocess running the program # 
child = subprocess.Popen(["java","findTheAverage"],bufsize = 0, universal_newlines = True, stdout = subprocess.PIPE, stdin = subprocess.PIPE) 

# stuff to stop IO blocks in child.stdout and sys.stdin ## (I stole if from http://stackoverflow.com/a/8980466/2674170) 
fcntl.fcntl(child.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 
fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 

# this here in the unlikely event that the program has # 
# finished by the time the main loop is first running # 
# because if that happened the loop would end without # 
# having added the programs output to the string!  # 
progout = "" 
typedbuf = "#" 

### here we have the main loop, this friendly fellah is 
### going to read from the program and user, and tell 
### each other what needs to be known 
while True: 

## stop when the program finishes and there is no more output 
    if child.poll() != None and not progout: 
    break 

# read from 
    typed = "" 

    while typedbuf: 
    try: 
     typedbuf = sys.stdin.read(1) 
    except: 
     break 
    typed += typedbuf 
    stringbuf = "#" 
    string += typed 
    child.stdin.write(typed) 

    progout = "" 
    progoutbuf = "#" 
    while progoutbuf: 
    try: 
     progoutbuf = child.stdout.read(1) 
    except: 
     typedbuf = "#" 
     break 
    progout += progoutbuf 
    if progout: 
    print(progout) 
    string += progout 

# the final output string # 
print(string) 
+0

我不明白「子流程的輸出以及與之相關的用戶輸入」。應該是什麼意思? – Alfe

+0

編輯;現在更清楚了嗎? thx反饋btw。 – GreenT

+0

是的,這更清楚。 – Alfe

回答

1

您需要select在同一時間從多個源讀取(在你的情況下,標準輸入和孩子的輸出處理)。

import select 

string = '' 
while True: 
    r, w, e = select.select([ child.stdout, sys.stdin ], [], []) 
    if child.stdout in r: 
    string += child.stdout.read() 
    if sys.stdin in r: 
    typed = sys.stdin.read() 
    child.stdin.write(typed) 
    string += typed 

你仍然需要找到一個合適的斷裂狀態離開該循環。但你可能已經明白了。

我想在這一點上給出一個警告:寫入管道的進程通常會緩存到最新的可能時刻;你可能不會這樣想,因爲當從命令行(在終端中)測試相同的程序時,通常只有線路被緩衝。這是由於性能方面的考慮。在寫入終端時,通常用戶希望儘快看到輸出。在書寫管道時,通常閱讀過程很樂意給予更大塊,以便在到達之前更長時間地睡眠。

+0

謝謝,'選擇'絕對是我失蹤的東西。我仍然在做一些奇怪的事情,但它們應該更容易修復。 – GreenT

+0

關於你的新方面,我想這可能來自緩衝。你可以改變子程序的代碼,以便正確地清理它的輸出嗎?或者孩子的代碼不在你的控制範圍之內? – Alfe

+0

childeren程序是由用戶編寫的簡單程序,新用戶是java(或任何其他語言,我可以添加支持),所以我寧願不依賴於編輯它們。 目的是從一堆hello world類型的程序中獲取輸入和輸出以證明它們正常工作,然後製作一個可發送給教師的TeX文檔。 – GreenT