2013-05-06 64 views
0

我在Windows上遇到了Popen和Pipes問題。我認爲Popen在stdout和stderr之間混合了數據。 當我的程序只讀取標準輸出時,一切正常,但是當我讀取標準輸出和標準錯誤時,標準輸出中的一些數據被拋到標準錯誤。Popen混合數據流?

for line in iter(self._read_obj.readline, b''): 
     self._queue.put(line) 
     sleep(.2) 

哪裏self._read_obj或者是標準錯誤或標準輸出: 我的讀法。 你知道我該如何解決這個問題?

回答

0
from subproccess import * 
x = Popen('sh /root/script.sh', stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=True) 
print x.stdout.readline() 
print x.stderr.readline() 

由於您沒有發佈任何相關的代碼,所以下面是它的外觀。 請注意,readline仍然會提供輸出,即使沒有可讀取的輸出,stderr有時會「掛起」等待輸出,但如果您使用的是子進程,這是要走的路。

from subprocess import PIPE, Popen 
x = Popen(['ls', '-l'], stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=False) 
while 1: 
    if x.poll() != None: 
     break 
    _queue.put(x.stdout.readline()) 
    sleep(0.2) 

類似的東西應該工作。 如果您不需要兩個輸出分開,你只是想讀取數據,並將其ATT到一個隊列,你可以這樣做:

x = Popen(['ls', '-l'], stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=False) 

這裏就是我通常做

(和我不是說這是事物的最佳實踐,但它的工作原理)

from threading import Thread, enumerate 
from subprocess import Popen, PIPE 
from time import sleep 

class nonBlockingStderr(Thread): 
    def __init__(self, handle): 
     self.handle = handle 
     self.stderrOutput = [] 
     Thread.__init__(self) 
     self.start() 
    def stderr(self): 
     if len(self.stderrOutput) <= 0: 
      return '' 
     else: 
      ret = self.stderrOutput[0] 
      self.stderrOutput = self.stderrOutput[1:] 
      return ret 
    def run(self): 
     while 1: 
      line = self.handle.readline() 
      if len(line) > 0: 
       self.stderrOutput.append(line) 
      sleep(0.1) 

from subprocess import PIPE, Popen 
x = Popen(['ls', '-l'], stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=False) 
errHandle = nonBlockingStderr(x.stderr) 
while 1: 
    if x.poll() != None: 
     break 
    _queue.put(errHandle.stderr()) 
    _queue.put(x.stdout.readline()) 
    sleep(0.2) 
+0

對不起。是的,我正在使用子流程,但我不能總是「等待」readline,所以我的方式對我更好。 – Tomek 2013-05-06 11:11:55

+0

@Tomek無論如何,我已經告訴你如何分離兩個輸出(這是你的原始問題)。這裏有一個方法來處理stderr,以便它不會阻止你的代碼,同時仍然可以讀取stdout,你也可以以類似的方式放置stdout,但出於說明的目的,我已經把它留下了。 – Torxed 2013-05-06 11:19:30

+1

我不知道如何...但它的作品 - 我的方式是類似的,我試過了: Popen('long cmd string',shell = True,stdout ...) 感謝您的時間:) – Tomek 2013-05-06 11:48:58

0

一個簡單的方法來分離標準輸出/ stderr輸出是使用.communicate()

from subprocess import Popen, PIPE 

p = Popen(command, stdout=PIPE, stderr=PIPE) 
out, err = p.communicate() 

它讀取內存中的所有輸出。

如果您想在子流程運行時處理輸出;你需要Windows上的線程:

from Queue import Empty, Queue 
from subprocess import Popen, PIPE 
from threading import Thread 

def reader_thread(pipe, process_line): 
    for line in iter(pipe.readline, b''): 
     process_line(line) 
    pipe.close() 

def start_reader_thread(pipe, process_line): 
    t = Thread(target=reader_thread, args=[pipe, process_line]) 
    t.daemon = True 
    t.start() 

q = Queue() 
p = Popen(command, stdout=PIPE, stderr=PIPE, bufsize=1) 
start_reader_thread(p.stdout, lambda line: q.put(('stdout', line))) 
start_reader_thread(p.stderr, lambda line: q.put(('stderr', line))) 

while p.poll() is None: # while subprocess is running 
    try: 
     source, line = q.get_nowait() 
    except Empty: 
     pass 
    else: 
     # use source, line here 
     print(source, line) 
q.put(None) 
for source, line in iter(q.get, None): # process the rest 
    # use source, line here 
    print("after", source, line)