ubuntuusers.de

[Python] Problem mit Pipes

Status: Ungelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

Barabbas

Avatar von Barabbas

Anmeldungsdatum:
31. März 2007

Beiträge: 1651

Wohnort: Münster

Hallo zusammen,

ich versuche mich gerade an Pipes unter Python.

An sich ist das Ganze kein Problem:

import subprocess
p = subprocess.Popen(["ls", "-als"], stdout=subprocess.PIPE)
output = p.communicate()[0]
print output

gibt wie erwartet den Verzeichnisinhalt aus.

Allerdings möchte ich ein "frontend" für wget schreiben. Die Pipe gibt aber erst einen Wert zurück, wenn das Programm abgelaufen ist - was bei wget und großen Dateien ewig dauern kann.

würde ich etwa obiges beispiel etwa so abändern, dass ls alle Dateien der gesamten root- Partition ausgeben soll, bekäme ich die rückgabe erst, wenn der prozess schon durchgelaufen ist.

import subprocess
p = subprocess.Popen(["ls", "-Rals", "/"], stdout=subprocess.PIPE)
print p.communicate()[0]

Für mein wget- Frontend möchte ich natürlich eine andauernde Aktualisierung, um etwa den Fortschritt anzuzeigen.

Hat jemand eine Idee?

lG

brb

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

Das zurückgegebene Popen-Objekt hat ein stdout Attribut, welches die Pipe als File-Objekt darstellt. Darüber kannst du einfach iterieren, um die Ausgabe zeilenweise zu lesen.

Kopfgeldjaeger

Anmeldungsdatum:
24. Dezember 2006

Beiträge: 1168

In dem speziellen Fall würd ich das ganze lieber ganz selbst schreiben (urllib(2), etc.).

mfg

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

Kopfgeldjaeger hat geschrieben:

In dem speziellen Fall würd ich das ganze lieber ganz selbst schreiben (urllib(2), etc.).

Mit urllib allein wirst du da nicht weit kommen. Wget macht noch einiges mehr (u.a. Parsen von Seiten für rekursiven Download, ftp-Unterstützung, etc.). Ich würde eher schauen, ob es nicht ein Python-Binding für libcurl gibt. Damit dürfte man WGets Funktionalität schon eher nahekommen 😉

Barabbas

(Themenstarter)
Avatar von Barabbas

Anmeldungsdatum:
31. März 2007

Beiträge: 1651

Wohnort: Münster

Ah, vielen Dank für den Tipp. Ich möchte es gerne von "Hand" machen, weil ich mich einfach ein wenig in die Pipes reinfuchsen will - außerdem gibt es halt sehr viele gute Shell- Tools, die man ja nicht neu schreiben muss sondern besser in eine GUI einbindet, wenn man sie grafisch haben möchte.

Ich habe es jetzt mit dem .stdout versucht, der Code sie wie folgt aus:

url = "http://ls.releases.ubuntu.com/7.10/ubuntu-7.10-desktop-i386.iso"
style = "--progress=bar" #dot
p = subprocess.Popen(["wget", "-c", style, url], stdout=subprocess.PIPE, stderr = subprocess.PIPE)
#p = subprocess.Popen(["watch", "ls", "-als"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#p = subprocess.Popen(["ls", "-Rals", "/"], stdout=subprocess.PIPE, stderr = subprocess.PIPE)
print "ok"
for line in p.stdout.readlines():
    print line

Das sollte ja das sein, was du meintest. Allerdings habe ich da genau das gleiche Problem, die Ausgabe erfolgt erst, wenn der aufgerufene Prozess durchgelaufen ist (z.B. auch bei dem auskommentierten dritten Popen.

Ich hoffe, ich stelle mich nicht allzu dumm an, wüsste aber wirklich nicht, wo mein Denkfehler sitzt.

lG und vielen Dank

brb

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

Erstmal kannst du readlines weglassen. Readlines ist veraltet, Dateiobjekte sind mittlerweile direkt iterierbar. Schreibe einfache for line in p.stdout:.

Zur Lösung des eigentlichen Problems: Die meisten Programme schreiben nicht ungepuffert auf die Standardausgabe, sondern speichern intern zwischen. Dadurch kommen die Daten nicht in der Pipe an, wodurch das Skript blockiert: http://www.python-forum.de/topic-9133.html?postdays=0&postorder=asc&highlight=subprocess

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4686

Wohnort: Berlin

Der Denkfehler liegt bei dem .readlines(), das ist eine Methode, die alle Zeilen liest, dass heisst die ``for``-Schleife geht erst los, wenn alle Zeilen in eine Liste eingelesen wurden. Lass diesen Methodenaufruf einfach weg. Dateiobjekte selbst sind "iterierbar" und geben die einzelnen Zeilen zurück.

Antworten |