Seite 1 von 1
Ausgabe von Programm einlesen
Verfasst: Freitag 21. September 2007, 15:14
von samy-delux
Hey Leute,
Ich würde gerne in meinem Python Programm ein anderes Programm aufrufen und davon den output einfangen und in einer Variable speichern!
Ich habe jetzt eine halbe Stunde gesucht und die Module posix, subprocess und os ausprobiert, doch ich bekomme es einfach nicht gebacken!
Die Sache ist doch bestimmt ganz einfach oder?
so long,
Samy
Verfasst: Freitag 21. September 2007, 15:19
von Hyperion
Hallo,
das kannst Du ganz einfach mit popen() machen! Hab grad kein Python zur Verfügung, aber ist echt einfach. Guck mal in der Doku bei "os" nach. iirc steht da was dazu. Ist eigentlich wie ne Datei, also ca. folgendes Schema (ungetestet):
Verfasst: Freitag 21. September 2007, 15:28
von Rebecca
Ab Python 2.4 sollte man subprocess verwenden: [wiki]Neue Features#Subprocess[/wiki]
Verfasst: Freitag 21. September 2007, 15:47
von samy-delux
Mit subprocess würde ich es gerne machen, doch folgender Code funktioniert nicht:
Code: Alles auswählen
process = subprocess.Popen(["du", "--max-depth=0 "+dir], stdout=subprocess.PIPE)
process.wait()
print process.stdout.read()
Die Ausgabe ist:
Was mache ich da falsch?
so long,
Samy
Verfasst: Freitag 21. September 2007, 15:53
von Hyperion
Rebecca hat geschrieben:Ab Python 2.4 sollte man subprocess verwenden: [wiki]Neue Features#Subprocess[/wiki]
Wußte ich noch nicht. Man lernt nie aus

Verfasst: Freitag 21. September 2007, 16:05
von Rebecca
Bei mir klappt es so, man beachte den Unterschied bei der Parameteruebergabe fuer du:
Code: Alles auswählen
>>> process = subprocess.Popen(["du", "--max-depth=0", "/home/rbreu"], stdout=subprocess.PIPE)
>>> process.wait()
>>> print process.stdout.read()
18360840 /home/rbreu
Verfasst: Freitag 21. September 2007, 16:11
von samy-delux
ok, danke!
Es lag an der übergabe der Argumente!
Verfasst: Sonntag 23. September 2007, 00:24
von samy-delux
Hm, ich habe gerade wieder ein Problem:
Ich will gerne alle Dateien die es in einem Verzeichnis + Unterverzeichnissen gibt einlesen. Das geht auf der Konsole ja ganz einfach mit:
Insgesamt erzeugt das 2006 Zeilen (mit einem "wc -l" gemessen) und funktioniert auf der Konsole wunderbar.
Wenn ich nun jedoch folgenden Python Code probiere das gleiche machen zu lassen, macht er einfach nichts und das für mehrere Stunden:
Code: Alles auswählen
import subprocess
dir = "/directory"
process = subprocess.Popen(["find", dir, "-name", "*"], stdout=subprocess.PIPE)
process.wait()
print process.stdout.read()
Wenn ich allerdings das Suchmuster etwas eingrenze, dann geht das ganze wunderbar. Ich habe es mit "*html" als Suchmuster versucht was mit 434 Ergebnisse liefert. Das funktioniert dann sowohl auf der Shell als auch in Python wunderbar!
Irgendwas läuft da schief!
Verfasst: Sonntag 23. September 2007, 07:23
von pug
Hallo
ich vermute, dass Du den Parameter * noch in Hochkommas schreiben musst also: "'*'".
Da Du ja bei deinem ursprünglichen Befehl auch den * in Hochkomma hast.
Code: Alles auswählen
import subprocess
dir = "/directory"
process = subprocess.Popen(["find", dir, "-name", "'*'"], stdout=subprocess.PIPE)
process.wait()
print process.stdout.read()
Grüße
Pug
Verfasst: Sonntag 23. September 2007, 09:02
von BlackJack
Die Vermutung habe ich auch, denn:
Code: Alles auswählen
bj@s8n:~$ find /directory -name *
find: paths must precede expression
Usage: find [-H] [-L] [-P] [path...] [expression]
Und diese Meldung kommt nicht auf `process.stdout` an, sondern auf `process.stderr`. Letzteres liest Du nie aus, damit beendet sich der Prozess nie, und das wiederum führt dazu, dass Du beim Lesen von `process.stdout` bis zum Sankt Nimmerleins-Tag warten kannst.
Verfasst: Sonntag 23. September 2007, 09:24
von lunar
Das sieht nur auf der Shell so aus (da ist der Asterik ja ein Sonderzeichen und muss korrekt gequoted werden). Allerdings umgeht subprocess die Shell und nutzt fork/execvp, um ein neuen Prozess zu starten. Die Argumente in der Liste kommen genau so, wie sie dastehen, bei find an:
Code: Alles auswählen
[lunar@nargond]-[10:10:34] >> /home/lunar
[2]--> subprocess.call(['find', '/home/lunar', '-name', '*'])
/home/lunar
/home/lunar/.htoprc
/home/lunar/Kalender.ics~
/home/lunar/.recently-used.xbel
/home/lunar/.bogofilter
/home/lunar/.bogofilter/wordlist.db
/home/lunar/.ktorrent.lock
...
Es funktioniert also auch ohne Quoting. Im Gegenteil, ich glaube sogar, dass es mit Hochkomma gar nicht funktioniert, weil find dann nach Dateien sucht, die dieses Hochkomma enthalten (find sieht das Hochkomma ja, da die Shell nicht dazwischen funkt).
Edit: wait scheint bei meinen Versuchen ebenfalls zu hängen, allerdings sieht subprocess ja eigentlich auch eine andere Methode vor, um mit dem Unterprozess zu kommunizieren:
Code: Alles auswählen
process = subprocess.Popen(['find', '/directory', '-name', '*'], stdout=subprocess.PIPE)
stdout = process.communicate()[0]
print stdout
Damit funktioniert es auch.
Verfasst: Sonntag 23. September 2007, 09:27
von BlackJack
Argh, stimmt.

Ist noch zu früh.

Verfasst: Sonntag 23. September 2007, 11:38
von samy-delux
Super, so funktioniert es!
Vielen Dank für die super Hilfe hier!
Nochmal ne kurze Rückfrage: Es ist also generell besser den Output mit "process.communicate()[0]" zu holen, anstatt erst "process.wait()" zu machen und dann den Output anzufragen?
Verfasst: Sonntag 23. September 2007, 17:45
von lunar
Nein.
Python Doku hat geschrieben:Note: The data read is buffered in memory, so do not use this method if the data size is large or unlimited.
Wenn du große Mengen an Daten aus der Pipe lesen willst, dann solltest du communicate nicht nutzen. wait() funktioniert offenbar allerdings auch nicht. Ich denke mal, dass das daran liegt, dass der Pufferspeicher der Pipe zuläuft und find so nichts mehr auf stdout schreiben kann und deswegen einfriert, bis du aus stdout liest.
Um richtig große Mengen an Daten einzulesen, würde sich also vielleicht eher sowas anbieten:
Code: Alles auswählen
process = subprocess.Popen(['find', '/directory', '-name', '*'], stdout=subprocess.PIPE, bufsize=1)
while True:
line = process.stdout.readline()
if not line:
break
# die Zeile hier verarbeiten
Dadurch sparst du dir das Anlegen einer endlosen Liste. Wenn der Speicherverbrauch allerdings egal ist, dann kannst imho auch communicate verwenden.
Verfasst: Sonntag 23. September 2007, 17:57
von BlackJack
Direkt über `process.stdout` iterieren geht nicht?
Verfasst: Sonntag 23. September 2007, 18:01
von lunar
BlackJack hat geschrieben:Direkt über `process.stdout` iterieren geht nicht?
Doch, wahrscheinlich schon

Hab irgendwie nicht daran gedacht...
Auf die Uhrzeit kann ich das jetzt nicht schieben... aber vielleicht auf den fehlenden Kaffee heute Nachmittag
