Subprocess Ausgabe ohne Zeilenumbruch lesen und verarbeiten

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.
Antworten
trequ
User
Beiträge: 6
Registriert: Mittwoch 12. August 2009, 09:31

Hallo.

Ich bin was Python angeht ein Einsteiger und werde aus sys.stdout.flush() nicht schlau.

Ich habe ein Python Script das mehrere andere Python Scripts aufrufen soll.
Die einzelnen Scripts machen dann etwas und geben einen Status aus, ähnlich dem Linux Startvorgang.

Beispielausgabe:

Code: Alles auswählen

Startup !
 Starte Script /scripts/test1.py ...
    Startup Taskscript 1!
      Lasse Aktion 1 laufen... OK
      Lasse Aktion 2 laufen... OK
      Lasse Aktion 3 laufen... OK
    Taskscript 1 End!
 Starte Script /scripts/test2.py ...
    Startup Taskscript 2!
      Lasse Aktion 1 laufen... OK
      Lasse Aktion 2 laufen... OK
      Lasse Aktion 3 laufen... OK
      Lasse Aktion 4 laufen... OK
      Lasse Aktion 5 laufen... OK
    Taskscript 2 End!
End!
Weiterhin soll die Ausgabe von dem Script auch in ein Logfile geschrieben werden.
Soweit ist das nicht weiter schwer und das krieg ich auch hin.

Mein Problem ist folgendes:
Zwischen der Ausgabe von "Lasse Aktion X laufen..." und dem OK vergeht ja einige Zeit in der der eigentliche Prozess im Sub-Script läuft.
Erst dann kommt die Ausgabe von OK und der Zeilenumbruch.
readline() liest aber ja nur wenn ein Zeilenumbruch da ist.
Wie bilde ich das jetzt ab, wenn ich keinen Zeilenumbruch habe?

Hier sind meine Test-Scripte:
test.py:

Code: Alles auswählen

#!/usr/bin/env python
import os, time, sys, subprocess
print "Startup !"

scripts = ["test1.py", "test2.py"]#
path = "//scripts"

for script in scripts:
  script = path + "/" + script
  print " Starte Script " + script + " ..."
  sp = subprocess.Popen(script, cwd=os.path.dirname(script), stdout=subprocess.PIPE, universal_newlines=True, stderr=subprocess.STDOUT,stdin=None)
  for line in iter(sp.stdout.readline, ""):
    line = line.rstrip("\n")
    print "    " + line
    sys.stdout.flush()
print "End!"
test1.py:

Code: Alles auswählen

#!/usr/bin/env python
import time, sys

print "Startup Taskscript 1!"
for l1 in range (1,4):
  print "  Lasse Aktion %s laufen..." % l1,
  sys.stdout.flush()
  time.sleep(1)
  print "OK"
print "Taskscript 1 End!"
test2.py:

Code: Alles auswählen

#!/usr/bin/env python
import time, sys

print "Startup Taskscript 2!"
for l1 in range (1,6):
  print "  Lasse Aktion %s laufen..." % l1,
  sys.stdout.flush()
  time.sleep(1)
  print "OK"
print "Taskscript 2 End!"
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

1. Du brauchst kein sys.stdout.flush()
2. Es gibt ``sp.communicate()`` das liefert dir die Ausgabe des Prozesses als Liste - eigtl als Tuple von Listen.

http://docs.python.org/library/subprocess.html
http://docs.python.org/library/subproce ... ommunicate
trequ
User
Beiträge: 6
Registriert: Mittwoch 12. August 2009, 09:31

Hallo.

Das funktioniert so aber leider nicht.
Bisher bekomme ich die Ausgabe wenigstens Zeilenweise, damit kann ich jede Zeile entsprechend einrücken.

Ich habe es mit communicate probiert:
test.py:

Code: Alles auswählen

#!/usr/bin/env python
import os, time, sys, subprocess
print "Startup !"

scripts = ["test1.py", "test2.py"]#
path = "/scripts"

for script in scripts:
  script = path + "/" + script
  print " Starte Script " + script + " ..."
  sp = subprocess.Popen(script, cwd=os.path.dirname(script), stdout=subprocess.PIPE, universal_newlines=True, stderr=subprocess.STDOUT,stdin=None)
  output = sp.communicate()[0]
  print "    " + output
  #for line in iter(sp.stdout.readline, ""):
  #  line = line.rstrip("\n")
  #  print "    " + line
  sys.stdout.flush()
print "End!"
Dann passiert aber folgendes:
Es wird ausgeben:

Code: Alles auswählen

Startup !
 Starte Script /scripts/test1.py ...
dann hängt alles bis test1.py fertig ist und dann wird alles auf einmal ausgeben.
Weiterhin werden die 4 Leerzeichen nur am anfang der ersten Zeile und nicht bei jeder Zeile angefügt:

Code: Alles auswählen

    Startup Taskscript 1!
  Lasse Aktion 1 laufen... OK
  Lasse Aktion 2 laufen... OK
  Lasse Aktion 3 laufen... OK
Taskscript 1 End!
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

``output`` ist eine Liste, wenn du jede Zeile einruecken willst, musst du auch ueber die Liste iterieren.
Ich versteh dein Problem mit der Ausgabe nicht. Willst du das alles auf einmal kommt? Dann warte auch auf ``sp`` bzw verwende gleich ``subprocess.call``.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Nein, ich schätze, das übliche Problem. Er will jede einzelne Zeile sofort nach der Ausgabe, nicht alles am Prozessende auf einmal
vorlautboy
User
Beiträge: 38
Registriert: Sonntag 7. Dezember 2008, 18:43

cofi hat geschrieben:Ich versteh dein Problem mit der Ausgabe nicht. Willst du das alles auf einmal kommt? Dann warte auch auf ``sp`` bzw verwende gleich ``subprocess.call``.
Er will die Ausgabe je Zeile auf zwei Schritte aufteilen:
I. Starte Skript x ... [Jetzt wird das Skript ausgeführt] ... II. OK
trequ
User
Beiträge: 6
Registriert: Mittwoch 12. August 2009, 09:31

Jein.

Ich startet ein Script, welches dann selbst mehere Zeilen ausgibt und immer OK dahinter schreibt.

Ich habs jetzt so gelöst:

Code: Alles auswählen

  sp = subprocess.Popen(script, cwd=os.path.dirname(script), stdout=subprocess.PIPE, universal_newlines=True, stderr=subprocess.STDOUT,stdin=None)

  line = ""
  while True:
    char = sp.stdout.read(1)
    sys.stdout.write(char)
    sys.stdout.flush()
    if char == "\n":
      # line ins log schreiben ... 
      line = ""
    else:
      line = line + char
    if char == "" and  sp.poll() != None: break
lunar

cofi hat geschrieben:``output`` ist eine Liste, wenn du jede Zeile einruecken willst, musst du auch ueber die Liste iterieren.
RTFM! "output" ist keine Liste, sondern eine einzige geschlossene Zeichenkette mit dem gesamten Inhalt der Standardausgabe des Unterprozesses!
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@cofi: Und falls du die Ausgabe von `communicate()` meintest, das ist ein Tupel: (stdout, stderr).
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

@lunar: Right, ich frag mich nur, warum ich auf die Listen kam ...

@snafu: Erm ... das sagte ich doch oO
cofi hat geschrieben:2. Es gibt ``sp.communicate()`` das liefert dir die Ausgabe des Prozesses als Liste - eigtl als Tuple von Listen.
Antworten