subprocess Ausgaben in "Echtzeit" verabeiten

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.
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 23. Oktober 2008, 10:06

Edit (jens): Abgetrennt von: http://www.python-forum.de/topic-16346.html

Was haltet ihr hiervon:

Code: Alles auswählen

# -*- coding: utf-8 -*-

import sys, subprocess

IS_WIN = (sys.platform == "win32")

cmd = ["ping", "127.0.0.1"]
if not IS_WIN:
    cmd.append("-c 5")

print " ".join(cmd)
p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE)

line = ""
while p.poll() is None:
    char = p.stdout.read(1)
    if char == "\n":
        print line
        line = ""
    elif IS_WIN and char == "\r":
        continue
    else:
        line += char

print "--- END ---"
Zuletzt geändert von jens am Freitag 24. Oktober 2008, 11:09, insgesamt 1-mal geändert.

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

Donnerstag 23. Oktober 2008, 10:39

@jens: Nun muss ich mich aber echt zusammenreissen um nichts beleidigendes zu antworten.

Du hast das Problem vom OP anscheinend nicht verstanden und ich weiss nicht einmal wofür dass da eine Lösung sein soll.
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 23. Oktober 2008, 10:43

Sorry, ich hab den Thread nicht komplett gelesen :oops:

Ich hatte selber nach einer Lösung gesucht und bin auf diesen Thread gestoßen. Ich wollte eigentlich die Ausgaben von einem subprocess lesen, aber gleichzeitig auch anzeigen lassen. Dachte hier geht's um das selbe...

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:

Freitag 24. Oktober 2008, 11:10

So, ich hab es mal Abgetrennt vom Ursprünglichen Thread: http://www.python-forum.de/topic-16346.html

Irgendwie ist es auch blödsinn mit read(1) zu arbeiten. readline macht da mehr Sinn:

Code: Alles auswählen

# -*- coding: utf-8 -*-

import os, sys, subprocess

def auswertung(line):
    """
    Hier kann die Ausgabe verarbeitet werden.
    """
    out = "[%-77s]" % line.strip()
    print out

def test(cmd):
    print " ".join(cmd)
    print "-"*79
    p = subprocess.Popen(
        cmd,
        stdout=subprocess.PIPE,
        shell=False,
    )
    while True:
        line = p.stdout.readline()
        auswertung(line)
        if line=="":
            break


if sys.platform == "win32":
    switch = "-n"
else:
    switch = "-c"

cmd = ["ping", switch, "3", "127.0.0.1"]
test(cmd)


print "--- END ---"
EDIT: Das könnte man auch noch kombinieren mit einem Timeout, siehe:
http://www.python-forum.de/post-96795.html#96795
http://trac.pylucid.net/browser/trunk/p ... rocess2.py

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:

Donnerstag 30. Oktober 2008, 16:04

Was ich mich nun Frage, kann man ein Process starten und auf ihn warten. Dabei sollen seine Ausgaben in der shell Sichtbar sein. Wenn der Process fertig ist, brauche ich aber dann auch die Ausgaben in Python.

Wie kann man das machen?

Mir fällt da nur wieder diese .read(1) Lösung ein:

Code: Alles auswählen

    p = subprocess.Popen(
        cmd,
        stdout=subprocess.PIPE,
        shell=False,
    )
    buffer = ""
    while True:
        char = p.stdout.read(1)
        if char=="":
            break

        buffer += char
        sys.stdout.write(char)
        sys.stdout.flush()

    auswertung(buffer)

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Freitag 31. Oktober 2008, 09:11

Hi

Damit funktionierts nicht?
http://www.python-forum.de/post-112880.html#112880

Gruss
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 31. Oktober 2008, 14:47

Das ist allerdings eine Windows-only Lösung. Nicht so schön...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Freitag 31. Oktober 2008, 16:34

Für eine Linux-Lösung siehe den Post über dem zitierten.
MfG
HWK
Qubit
User
Beiträge: 75
Registriert: Dienstag 7. Oktober 2008, 09:07

Freitag 31. Oktober 2008, 16:43

jens hat geschrieben:Was ich mich nun Frage, kann man ein Process starten und auf ihn warten. Dabei sollen seine Ausgaben in der shell Sichtbar sein. Wenn der Process fertig ist, brauche ich aber dann auch die Ausgaben in Python.

Wie kann man das machen?
Mal zum Verständnis:
Prozesse haben 3 Standardpipes: IN,OUT,ERR.
"Popen" startet einen Prozess und kann nun die Pipes dieses Prozesses in dessen Prozessraum setzen (über PIPE). Die gestartete Applikation schreibt i.a. in STDOUT. Ändert man diese PIPE schreibt er auch nichts mehr auf die Konsole. Belässt man ihn, werden keine Ausgaben an "subprocess" gepiped.
Entweder öffnet die Applikation zusätzliche PIPES, über die man an Daten rankommt oder man muss die Daten selbst duplizieren und den Descriptor auf den STDOUT des (Sub-) Prozesses setzen, ähnlich wie es "tee" unter Unix macht.
Vielleicht kann man "subprocess" dahingehend patchen, so dass STDOUT dupliziert wird und eine PIPE an "subprocess" hängt. Standardmäßig ist das aber nicht implementiert ;-)
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 31. Oktober 2008, 16:50

Also ich hab mir den subprocess.py code schon mal angesehen. Ich hab in der Richtung nicht wirklich was finden können.

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:

Dienstag 4. November 2008, 18:01

Das eigentliche Problem ist, wenn das aufgerufene Programme kein stdout.flush() macht, geht die "Echtzeitanzeige" nicht...
rayo hat geschrieben:Damit funktionierts nicht?
http://www.python-forum.de/post-112880.html#112880
...auch damit nicht :(

Beispiel, zum selber testen hier: http://paste.pocoo.org/show/90128/

Irgendwelche Lösungen dafür???

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

Dienstag 4. November 2008, 20:10

Nein. Wenn die Daten nicht in der Pipe, sondern noch im Puffer liegen, gibt es nichts, was man lesen könnte.
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 5. November 2008, 08:57

Das Leuchtet mir eigentlich ein. Aber: In der Konsole sehe ich ja auch die Ausgabe und das ohne Verzögerung.

Könnte also eine Lösung darin bestehen, eine Konsole zu emulieren???

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:

Mittwoch 5. November 2008, 10:56

Das Problem wird in der FAQ von Pexpect ganz gut erklärt: http://www.noah.org/wiki/Pexpect#Q:_Why ... 8.29.29.3F

So wie ich es verstehe:
Oft nutzten Programme die Standard C IO Library (stdio.h). Diese nutzt ein eigenen Puffer. Wenn das Programm nicht explizit ein stdout.flush() macht, dann wird erstmal der "interne" Puffer voll geschrieben und erst dann ausgegeben. Dabei weiß stdio.h ob es in eine Pipe schreibt oder in ein Terminal. In eine Pipe kommt ein "Block Puffer" zum einsatz, der größer ist, als der normale "Line Puffer".
Somit bekommt man aus der Pipe erst Daten wenn der Puffer voll ist, oder das Programm beendet ist.

Die Frage ist nun, kann man irgendwie die Puffer Größe beeinflussen und auf 1-Zeichen setzten, oder so tun als wenn man ein Terminal und nicht eine Pipe ist???
Es gibt die Angabe "bufsize" bei subprocess. Aber egal ob auf 0 oder 1 gesetzt, das änder nix, warum?

Kann man evtl. was mit startupinfo und creationflags machen???

Zum Thema Pseudo-Terminal gibt es unter Windows anscheinend nicht wirklich, siehe: http://www.noah.org/wiki/Pexpect#pty_module
Ich hab auch diesbezüglich gesucht, aber nichts gefunden. Irgendwie kann man was mit Cygwin machen, aber das scheint mir sehr Aufwendig zu sein.

EDIT: Hab das ganze mal unter Linux getestet. Eigentlich gibt es da das selbe Problem!
Zuletzt geändert von jens am Mittwoch 5. November 2008, 13:49, insgesamt 1-mal geändert.

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

Mittwoch 5. November 2008, 11:32

Die Angabe zu `bufsize` ändert nichts am Puffer des *anderen* Programms, sondern betrifft den Puffer auf "Deiner Seite" der Pipe.

Zum Terminal-Emulieren kann man Pexpect nehmen. Und ich glaube Rebecca hatte so etwas mal selbst implementiert und hier ins Forum gestellt.
Antworten