Seite 1 von 1

Subprocess Ausgabe ohne Zeilenumbruch lesen und verarbeiten

Verfasst: Freitag 14. August 2009, 07:42
von trequ
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!"

Verfasst: Freitag 14. August 2009, 08:05
von cofi
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

Verfasst: Freitag 14. August 2009, 08:21
von trequ
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!

Verfasst: Freitag 14. August 2009, 09:54
von cofi
``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``.

Verfasst: Freitag 14. August 2009, 10:14
von burli
Nein, ich schätze, das übliche Problem. Er will jede einzelne Zeile sofort nach der Ausgabe, nicht alles am Prozessende auf einmal

Verfasst: Freitag 14. August 2009, 11:00
von vorlautboy
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

Verfasst: Freitag 14. August 2009, 11:13
von trequ
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

Verfasst: Freitag 14. August 2009, 12:20
von 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!

Verfasst: Freitag 14. August 2009, 12:26
von snafu
@cofi: Und falls du die Ausgabe von `communicate()` meintest, das ist ein Tupel: (stdout, stderr).

Verfasst: Freitag 14. August 2009, 15:00
von cofi
@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.