Hallo,
ich starte in einem Python-Programm einen Prozess mit subprocess.Popen(), der einen läger dauernden Befehl mit vielen Ausgaben an stdout bzw. stderr ausführt (konkret: es handelt sich um einen Befehl eines Tools zur Versionsverwaltung. Er labelt auf einem Server ca. 30000 Dateien. Bei jedem Einzelschritt gibt es eine Ausgabe an stdout "<File> der Version <Version> wurde mit Label <Label> versehen". Evtl. Fehler gehen an stderr). Die Abarbeitung dieses Befehls dauert ca. 10 Min.
Mein Problem: ich möchte die anfallenden Daten 'online' verarbeiten, ohne das Ende des Prozesses abzuwarten. Verarbeiten heißt hier jede Ausgabe des laufenden Prozesses untersuchen, ob bestimmte Bedingungen erfüllt sind (und evtl. auf Fehler reagieren), umformatieren, ein Logging erzeugen und in einer Datei speichern.
Ich habe schon im www und auf diesem Forum gesucht, aber keine Antwort gefunden, wit der ich wirklich etwas anfangen kann.
Kann jemand helfen?
Ich arbeite unter WinXP mit Python 2.6 und wxPxyhton 2.8
Danke im Voraus
'Realtime'-Verarbeitung von vielen Daten an stdout/stderr
Du kannst in jedem Fall immer über das `stdout`-Attribut iterieren, um Daten zeilenweise abzuarbeiten:
Ob die Daten allerdings auch zeilenweise ankommen, hängt von den Puffer-Einstellungen des aufgerufenen Programms ab. Ich kenne mich mit XP nicht aus, unter Unix allerdings schalten die meisten Programm ihre Pufferung um, und senden geschlossen größere Datenblöcke anstatt einzelner Zeilen, wenn sie erkennen, dass stdout eine Pipe ist.
Code: Alles auswählen
process = Popen(command, stdout=PIPE)
for line in process.stdout:
do_something_with(line)
Danke lunar für die schnelle Antwort. Habs gleich ausprobiert:
... und erhalte folgende Fehlermeldung:
for line in process.stdout :
TypeError: 'NoneType' object is not iterable
Das "bla =" ... dient nur dazu, meine Ausgaben von den stdout-Ausgaben zu unterscheiden.
Was mache ich falsch?
Code: Alles auswählen
process = subprocess.Popen ( myCmd, stderr=subprocess.STDOUT )
process.communicate()
for line in process.stdout :
print "bla = ",line
for line in process.stdout :
TypeError: 'NoneType' object is not iterable
Das "bla =" ... dient nur dazu, meine Ausgaben von den stdout-Ausgaben zu unterscheiden.
Was mache ich falsch?
- cofi
- Python-Forum Veteran
- Beiträge: 4432
- Registriert: Sonntag 30. März 2008, 04:16
- Wohnort: RGFybXN0YWR0
Dir ist klar, dass sich dein ``Popen``-Aufruf komplett von lunars unterscheidet?
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
Oh Mist, das seh ich erst jetzt nach Deinem Hinweis!cofi hat geschrieben:Dir ist klar, dass sich dein ``Popen``-Aufruf komplett von lunars unterscheidet?

Hab das jetzt in mein Programm so eingebaut, läuft prima. Vielen Dank für die Hilfe

hi! irgendwie hab' ich so immer noch das problem, dass der child-prozess
erst beendet wird und ich dann die ausgabe des prozesses auswerten kann..
folgendes szenario:
"meinAusgabeProgramm":
lesescript:
wenn ich jetzt das lesescript starte, läuft "meinAusgabeProgramm" erst
komplett durch und dann wird auf einen schlag alles ausgegeben. wieso?
(winXP, python2.5)
hoffe, die frame ist jetzt nicht zu blöd....
erst beendet wird und ich dann die ausgabe des prozesses auswerten kann..
folgendes szenario:
"meinAusgabeProgramm":
Code: Alles auswählen
from time import sleep
for i in range(0, 10):
print "schnarch: %d" % i
sleep(1)
Code: Alles auswählen
import subprocess
prozess = subprocess.Popen(meinAusgabeProgramm, stdout=subprocess.PIPE)
for line in prozesss.stdout:
print "---> " + line
komplett durch und dann wird auf einen schlag alles ausgegeben. wieso?
(winXP, python2.5)
hoffe, die frame ist jetzt nicht zu blöd....
Die Einrückung Deiner Beispiele stimmt nicht. Prüfe bitte die Vorschau, bevor Du Deine Beiträge absendest.
Dein Problem ist die Pufferung. Die Ausgabe kommt bei Python nicht sofort an, sondern wird aus Performance-Gründen vom System zwischengespeichert. Auf der Konsole geschieht das zeilenweise, damit der Nutzer eben sofort alles sehen kann. Bei einer Pipe (also dem Aufruf als Unterprogramm) dagegen puffert das System größere Blöcke, damit das aufgerufene Programm schneller laufen kann. Deswegen werden die Daten in Deinem Fall letztlich auch blockweise ausgegeben.
Mit subprocess lässt sich das nicht vermeiden, da das aufgerufene Programm selbst bestimmt, wie der Puffer aussieht. Vielleicht aber hast Du Glück, einige Programme haben spezielle Optionen, um die Pufferung anzugeben.
Dein Problem ist die Pufferung. Die Ausgabe kommt bei Python nicht sofort an, sondern wird aus Performance-Gründen vom System zwischengespeichert. Auf der Konsole geschieht das zeilenweise, damit der Nutzer eben sofort alles sehen kann. Bei einer Pipe (also dem Aufruf als Unterprogramm) dagegen puffert das System größere Blöcke, damit das aufgerufene Programm schneller laufen kann. Deswegen werden die Daten in Deinem Fall letztlich auch blockweise ausgegeben.
Mit subprocess lässt sich das nicht vermeiden, da das aufgerufene Programm selbst bestimmt, wie der Puffer aussieht. Vielleicht aber hast Du Glück, einige Programme haben spezielle Optionen, um die Pufferung anzugeben.
- Defnull
- User
- Beiträge: 778
- Registriert: Donnerstag 18. Juni 2009, 22:09
- Wohnort: Göttingen
- Kontaktdaten:
Weil, wie schon erwähnt, die meisten Programme ihre Ausgabe puffern. Wenn dein Programm keinen "line buffered"-Modus anbietet, hast du auch wenig Chancen, daran etwas zu ändern.
Bottle: Micro Web Framework + Development Blog
Hi,
habe ein ähnliches Problem unter Linux.
Schicke einen Job mit Hilfe von "qsub" ab und versuche die JobID über den stdout herauszubekommen und dem Benutzer anzuzeigen. Das funktioniert auch soweit, nur sobald ich "-sync yes" angebe erhalte ich die Ausgabe erst, wenn das Programm beendet wurde.
Gibt es da eine andere Möglichkeit ? An sys.stdout wird die Ausgabe sofort weitergeleitet, bei einer PIPE habe ich wohl das oben genannte Problem.
Ansonsten werde ich es wohl mit einem Shellscript versuchen müssen.
Edit: Bei einem Shellscript habe ich wohl das gleiche Problem
habe ein ähnliches Problem unter Linux.
Schicke einen Job mit Hilfe von "qsub" ab und versuche die JobID über den stdout herauszubekommen und dem Benutzer anzuzeigen. Das funktioniert auch soweit, nur sobald ich "-sync yes" angebe erhalte ich die Ausgabe erst, wenn das Programm beendet wurde.
Gibt es da eine andere Möglichkeit ? An sys.stdout wird die Ausgabe sofort weitergeleitet, bei einer PIPE habe ich wohl das oben genannte Problem.
Ansonsten werde ich es wohl mit einem Shellscript versuchen müssen.
Edit: Bei einem Shellscript habe ich wohl das gleiche Problem
@Bitzkit: Das `pexpect`-Modul (nicht in der Standardbibliothek) könnte eventuell eine Lösung sein.
Habe es mal mit pexpect versucht.
Damit erhalte ich die Ausgabe leider auch erst, sobald das Programm beendet wurde. Das Modul scheint aber auch recht komplex. An welche Methode hattest du gedacht ?
Schon mal danke.
Code: Alles auswählen
process = pexpect.spawn("qsub %s" % (os.path.join(path, "cmd")))
a = process.readline()
print a
Schon mal danke.