2009-05-19 4 views
4

Say Ich schreibe diesen:Gibt es eine Möglichkeit, ein Dateihandle abzurufen, das von subprocess.Popen zurückgegeben wird?

from subprocessing import Popen, STDOUT, PIPE 
p = Popen(["myproc"], stderr=STDOUT, stdout=PIPE) 

Nun, wenn ich

line = p.stdout.readline() 

mein Programm tun wartet, bis die subprocess die nächste Zeile ausgibt.

Gibt es irgendeine Magie, die ich zu p.stdout tun kann, so dass ich die Ausgabe lesen könnte, wenn es da ist, aber nur sonst fortfahren? Ich suche etwas wie Queue.get_nowait()

Ich weiß, ich kann nur einen Thread zum Lesen p.stdout erstellen, aber nehmen wir an, ich kann keine neuen Threads erstellen.

Antwort

5

Verwenden Sie das select Modul in Standardbibliothek Python finden http://docs.python.org/library/select.html. select.select([p.stdout.fileno()], [], [], 0) gibt sofort ein Tupel zurück, dessen Einträge aus drei Listen bestehen: Die erste wird nicht leer sein, wenn in diesem Dateideskriptor etwas zu lesen ist.

+0

+1 Ich mag diese Lösung –

+0

Was genau zurückgegeben wird? Dies gibt noch keine Ahnung, wie viele Bytes es zu lesen gibt. – iElectric

+2

'select' gibt den Satz von Dateideskriptoren (unter denen Sie ihn übergeben haben) zurück, auf denen I/O ohne Blockierung ausgeführt werden kann. Wenn Sie dafür sorgen können, dass p.stdout nach der Tatsache auf "non-blocking" gesetzt wird (systemabhängig), können Sie einfach p.stdout.read (N) für einige große N posten und alle Bytes erhalten, die tatsächlich verfügbar sind. Wenn die nicht blockierende Option nicht verfügbar ist, können Sie nur 1 Byte gleichzeitig lesen und dann zu 'select' zurückkehren, bis Ihnen mitgeteilt wird, dass es keine weiteren gibt. Achten Sie darauf, die Bytes, die Sie gelesen haben, in eine Liste einzufügen und am Ende zu verbinden (viel schneller als + = 'weg auf Strings! -). –

8

Verwenden p.stdout.read(1) diese zeichenweise

lesen und hier ein vollständiges Beispiel ist:

import subprocess 
import sys 

process = subprocess.Popen(
    cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE 
) 

while True: 
    out = process.stdout.read(1) 
    if out == '' and process.poll() != None: 
     break 
    if out != '': 
     sys.stdout.write(out) 
     sys.stdout.flush() 
+0

DANKE! Ich weiß nicht, wie viele Fragen ich nach einer einfachen Antwort auf dieses Thema gefragt habe - das war es. Ich hatte auch versucht, Zeichen für Zeichen zu lesen, aber ich wusste nicht, wie ich überprüfen sollte, ob der Prozess abgeschlossen war ... die Umfrage wurde komplett verpasst() - duh. +1 – jkp

+1

+1 Diese Lösung ist möglicherweise für Windows geeignet, wo 'select' nicht für Dateideskriptoren funktioniert, die von' subprocess' Modul erstellt wurden. Hinweis: Wenn der Subprozess genügend Ausgabe auf stderr generiert, blockiert er möglicherweise, es sei denn, Sie lesen von ihm (OP leitet stderr auf stdout um ('stderr = STDOUT'), so wird dies nicht passieren). Verwenden Sie 'is', um mit' None' zu ​​vergleichen, z. B. 'wenn x nicht None ist:'. Sie könnten 'if out:' anstelle von 'if out! = '':' Verwenden (dies funktioniert sowohl für Bytestrings als auch für Unicode-Strings). Auch wenn "cmd" Block-Pufferung im nicht-interaktiven Modus verwendet, wird 'process.stdout' nichts erhalten, bis' cmd' den Puffer löscht. – jfs

+2

Ich glaube nicht, dass dies die Frage beantwortet, die gestellt wurde. Diese Methode blockiert bei read (1), wenn keine Ausgabe verfügbar ist. Es wurde nach einer Methode gefragt, die in diesem Fall nicht blockiert, sondern stattdessen etwas anderes tut. –