6 Stimmen

Abfangen von stdout eines anderen Prozesses in Python in Echtzeit

Ich möchte einen Systemprozess laufen lassen, die Ausgabe abfangen und sie in einem Python-Skript Zeile für Zeile in Echtzeit ändern.

Mein bester Versuch, bei dem vor dem Drucken gewartet wird, bis der Vorgang abgeschlossen ist, ist folgender:

#!/usr/bin/env python
import subprocess

cmd = "waitsome.py"
proc = subprocess.Popen(cmd, shell=True, bufsize=256, stdout=subprocess.PIPE)
for line in proc.stdout:
    print ">>> " + line.rstrip()

Das Drehbuch waitsome.py druckt einfach alle halbe Sekunde eine Zeile:

#!/usr/bin/env python
import time
from sys import stdout

print "Starting"
for i in range(0,20):
    time.sleep(0.5)
    print "Hello, iteration", i
    stdout.flush()

Gibt es eine einfache Lösung, um die subprocess um eine Iteration über die Ausgabe in Echtzeit zu ermöglichen? Muss ich Threads verwenden?

Früher habe ich Skripte in Perl geschrieben, und das war ein Kinderspiel:

open(CMD, "waitsome.py |");
while (<CMD>) {
    print ">>> $_";
}
close(CMD);

0 Stimmen

Entschuldigung, ich habe nur den ersten gesehen und dachte, es handele sich um ein Problem mit dem Unterprozess Pufferung, nicht die des übergeordneten Python-Skripts.

16voto

Alex Martelli Punkte 805329

Schleifen über eine Datei puffern unvermeidlich Dinge in ziemlich großen Stücken - ein bekanntes Problem mit allen Python 2.* Implementierungen. In Python 3.1 funktioniert es so, wie Sie es beabsichtigen, wobei die letzte Schleife leicht verändert ist:

for line in proc.stdout:
    print(">>> " + str(line.rstrip()))

Wenn ein Upgrade auf Python 3.1 unpraktisch ist (und ich weiß, dass das oft der Fall sein wird!), gehen Sie den umgekehrten Weg und schreiben Sie die Schleife auf altmodische Weise - die folgende Version der Schleife funktioniert so, wie Sie es in Python 2.* beabsichtigen:

while True:
    line = proc.stdout.readline()
    if not line:
        break
    print ">>> " + line.rstrip()

1 Stimmen

Ja, aber jetzt, wo Python 3.1 heraus ist (mit einer viel besseren Implementierung des gesamten I/O-Stacks), gibt es keinen Grund, bei 3.0 zu bleiben (es war definitiv eine Übergangsversion;-).

1 Stimmen

for line in iter(proc.stdout.readline, ''): print ">>>", line, könnte bei Python 2 anstelle der while-Schleife verwendet werden.

0voto

Jeff Younker Punkte 161

Diese ganze Sache kann in einem Iterator gekapselt werden als:

def subprocess_readlines(out):
    while True:
        line = out.readline()
        if not line:
            return
        yield line

Und aufgerufen als:

for line in subprocess_readlines(proc.stdout):
    print ">>>", line.rstrip()

0 Stimmen

Die Pufferung in Python hat sich stark verändert, seit ich die ursprüngliche Frage geschrieben habe :) Ja, was in Python 2.5 viel Aufwand erforderte, kann jetzt in ein paar Zeilen erledigt werden.

0 Stimmen

Ich verstehe nicht, wo subprocess_readlines für diesen Ansatz definiert werden muss. Können Sie das näher erläutern?

0 Stimmen

Ooops. Ich hatte nicht den Aufruf von subprocess_readlines() . Ich habe das gerade aktualisiert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X