Prozessausgabe on-the-fly formatieren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
McEnroe
User
Beiträge: 5
Registriert: Montag 5. Februar 2007, 13:21

Montag 5. Februar 2007, 13:31

Ich habe das folgende Problem:
Ich schreibe ein Script, das KDE aus den Quellen baut. Dazu müssen Programme wie "cmake", "make", "make install" usw. aufgerufen werden. Dazu genügt ein subprocess.call(). Jetzt will ich die Ausgabe aber formatieren (konkret: um einen Tabulator einrücken). Wenn ich das mit

Code: Alles auswählen

cmake = subprocess.Popen(cmakecall, stdout=subprocess.PIPE)
for line in cmake.communicate()[0].split("\n"):
   print "\t", line
return cmake.wait()
mache wird zwar alles formatiert, aber die Ausgabe erfolgt erst wenn der Prozess beendet ist (bei einem "make" - sehr lang).

Wie kriege ich die Formatierung "on-the-fly" hin, quasi "live" während der Prozess noch läuft hin?
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 5. Februar 2007, 13:50

Wie wäre es mit cmake.readline() in der for schleife?

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
McEnroe
User
Beiträge: 5
Registriert: Montag 5. Februar 2007, 13:21

Montag 5. Februar 2007, 14:06

Du meinst wahrscheinlich cmake.stdout.readline()...
Das gibt aber nur die erste Zeile aus.
readlines() wartet bis der Prozess fertig ist und gibt es erst dann aus.
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 5. Februar 2007, 14:28

Hm... Kommt IMHO auf den child-prozess an... Ob er ein flush macht...
Das geht bei mir jedenfalls (Windows):

Code: Alles auswählen

import sys, subprocess

command = "ping heise.de"

process = subprocess.Popen(
    command,
    shell   = True,
    stdout  = subprocess.PIPE
)
while 1:
    line = process.stdout.readline()
    if line == "": break
    sys.stdout.write(line)

print "ENDE"

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Montag 5. Februar 2007, 14:37

jens hat geschrieben:Hm... Kommt IMHO auf den child-prozess an... Ob er ein flush macht...
Das ist der Punkt!

Das ist eben das Problem an dem ich auch gescheitert bin und bisher keine Brauchbare Lösung habe: http://www.python-forum.de/topic-9133.html
Entweder der gestartete Prozess puffert oder nicht. Wen er puffer hat man eben Pech gehabt.

lg
McEnroe
User
Beiträge: 5
Registriert: Montag 5. Februar 2007, 13:21

Montag 5. Februar 2007, 14:43

Wie wird denn bestimmt ob ein Prozess puffert?

Und die Sache mit der Pufferung ist die, dass subprocess.call() bis auf die Formatierung ja genau das tut was ich will....

@jens:
1. Was bewirkt das shell=true eigentlich?
2. Was mach ich wenn in der Ausgabe Leerzeilen auftauchen sollten?
BlackJack

Montag 5. Februar 2007, 15:07

jens hat geschrieben:

Code: Alles auswählen

while 1:
    line = process.stdout.readline()
    if line == "": break
    sys.stdout.write(line)
Können wir das bitte etwas "pythonischer" schreiben:

Code: Alles auswählen

for line in process.stdout:
    sys.stdout.write(line)
    sys.stdout.flush()
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 5. Februar 2007, 15:11

BlackJack hat geschrieben:Können wir das bitte etwas "pythonischer" schreiben:
Ja, das sieht besser aus... Tut's aber nicht so richtig. Denn dann sehe ich die Ausgaben erst, wenn der Prozess fertig ist ;)

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

Montag 5. Februar 2007, 15:14

McEnroe hat geschrieben:Wie wird denn bestimmt ob ein Prozess puffert?
Das bestimmst Du entweder selbst beim öffnen einer Datei, bzw. hat das an dieser Stelle jedes Programm selbst in der Hand, oder die C-Bibliothek entscheidet anhand des Dateityps: Wenn es eine Datei ist, die direkt mit einem Terminal verbunden ist, dann wird zeilenweise gepuffert, sonst gibt's einen Blockpuffer.
1. Was bewirkt das shell=true eigentlich?
Es wird eine Shell gestartet, die dann das Programm startet. Wozu diese Indirektion in diesem Fall gut sein soll, weiss ich nicht.
2. Was mach ich wenn in der Ausgabe Leerzeilen auftauchen sollten?
Leerzeilen sind nicht wirklich leer sondern bestehen aus einem Zeilenende-Zeichen. Die leere Zeichenkette kommt wirklich nur wenn die Datei gar nichts mehr hergibt. Bei Pipes also nur dann, wenn die Gegenseite die Datei geschlossen hat. Aber eine ``for``-Schleife über die Datei ist sowieso etwas schöner.
BlackJack

Montag 5. Februar 2007, 15:17

jens hat geschrieben:
BlackJack hat geschrieben:Können wir das bitte etwas "pythonischer" schreiben:
Ja, das sieht besser aus... Tut's aber nicht so richtig. Denn dann sehe ich die Ausgaben erst, wenn der Prozess fertig ist ;)
Das könnte eventuell an der Pufferung von `file.xreadlines()` liegen, obwohl ich das noch nicht so ganz glaube.

Dann schreib's halt so:

Code: Alles auswählen

for line in iter(process.stdout.readline, ''):
    sys.stdout.write(line)
    sys.stdout.flush()
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 5. Februar 2007, 15:17

Bei mir unter Windows in SciTE öffnet sich bei shell=False ein cmd-Fenster. Bei shell=True halt nicht...

Lustig ist ein command = "chkdsk c:"... Der erste Teil sieht man Live, macht also wohl ein flush... Die beiden Nachfolgenden Teile nicht... Sehr konsistent :roll:

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 5. Februar 2007, 15:19

@BlackJack: Ja, so geht's...

Zum einfügen von TABs:

Code: Alles auswählen

for line in iter(process.stdout.readline, ''):
    sys.stdout.write("\t%s\n" % line.rstrip())

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 5. Februar 2007, 18:17

Könnten wir nun dazu übergehen, den ersten Parameter von subprocess.Popen generell als Liste/Tupel zu übergeben? Wunderbar, danke...
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 5. Februar 2007, 18:24

Wo ist denn dein Problem?

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Montag 5. Februar 2007, 18:28

Warum Leo?
http://docs.python.org/lib/node529.html
The executable argument specifies the program to execute. It is very seldom needed: Usually, the program to execute is defined by the args argument.[...]
Wo steht hier das ein iterable erwartet wird?
[...]Wunderbar, danke...[...]
*Eine-Tasse-Tee-rübereich-zur-Entspannung* ;)
Antworten