Ausgabe an den Standard Output überschreiben

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
Poisos
User
Beiträge: 6
Registriert: Freitag 24. Oktober 2008, 08:41

Hallo zusammen,
ist es möglich die Ausgabe an den Standard Output (stdout) an ausgewählten Stellen zu überschreiben?

Ich bin der Meinung das schon in mehrern Command Shell Tools gesehen zu haben (die nicht unbedingt in Python geschrieben wurden).

Mein Ziel ist es eine Art Fortschrittsanzeige als reine Textausgabe bereitzustellen. Also etwas in der Art:
Fortschritt: .............................. 100%

Die Punkte sollen inkrementell und relativ zum prozentualen Fortschritt des Prozesses ausgegeben werden. Das ist relativ einfach indem ich auf print verzichte und sys.stdout.write('.') verwende.
Nur die 100% am Ende müsste bei jeder Aktualisierung mit einer Art "seek" angesteuert und überschrieben werden (also 10%, 20% ...).

Die einzige Alternative die mir so einfällt wäre die gesamte Statusausgabe über eine Class zu verwalten und dann bei jedem Update sowas wie "cls" an der Command Line auszulösen (me = Windows User) gefolgt von der gesamten Ausgabe. Dies ist aber leider wohl plattformspezifisch und meines Erachtens nach nicht sonderlich elegant.

Ein weiterer gedanklicher Ansatz von mir war, dass stdout ja eigentlich "nur" ein stream ist. Daher sollte es doch möglich sein, eine ausgewählte Position im Stream anzusteuern!? (Sollte ich mich hier irren korrigiert mich bitte!) ... In einer Datei geht das doch auch!? Oder ist das nur auf ein input seek begrenzt?

Falls die Antwort "Nein - das geht nicht" sein sollte, würde ich mich über eine kurze Begründung freuen.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Moin,

so auf die Schnelle würde ich das folgendermaßen lösen. Vielleicht gibt es aber auch bessere Lösungen:

Code: Alles auswählen

import sys
import time
for i in xrange(10):
    sys.stdout.write('\r' + '.'*i + str(i*10) + "%")
    sys.stdout.flush()
    time.sleep(.2)
\r ist ein Wagenrücklauf, d.h. der Cursor wird auf den Anfang der Zeile gesetzt. Dann kannst du die Zeile neu aufbauen.

Gruß,
Manuel
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Poisos
User
Beiträge: 6
Registriert: Freitag 24. Oktober 2008, 08:41

@ helduel
Wow - Danke!
Diesem Lösungsansatz bin ich gedanklich nicht mal nahe gekommen!
Zwar ändert sich in Deinem Beispiel noch die Position der Prozentzahl, aber das sollte man/ich ja beim Neuaufbau der Zeile berechnen und durch entsprechende Leerzeichen abfangen können.

Ich kenn' aus Turbo Pascal noch GotoXY zur Positionierung des Cursors im Standard Outout. Kann man sowas in Python emulieren?

@ Y0Gi
Super Links! Ich kann nur den scrolling text nicht beenden. Er müsste ja bei 'nem KeyboardInterrupt aussteigen so wie ich das sehe. Aber kein Tastendruck schein zu funktionieren - nicht mal Escape. :?:

edit:
Ah! Hab 's! Ctrl+C (siehe Python Manual für KeyboardInterrupt ... delete, also Entfernen funktioniert bei mir trotzdem nicht)
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Ja, <Ctrl-C> löst einen KeyboardInterrupt aus. Wie kommst du auf <del>?

Wenn du direkt Koordinaten der Console ansprechen willst, willst du vermutlich einen Wrapper um/eine Schnittstelle zu ncurses, urwid o.ä. Ansonsten reicht das in den Snippets demonstriere Verfahren oft aus.

Poisos hat geschrieben:Zwar ändert sich in Deinem Beispiel noch die Position der Prozentzahl, aber das sollte man/ich ja beim Neuaufbau der Zeile berechnen und durch entsprechende Leerzeichen abfangen können.
Wie auch immer du den Fortschrittsbalken aktualisiert: er sollte ja eine feste Breite haben. Dahinter verwendest du einfach ``'%-3d' % percentage`` (iirc).
Poisos
User
Beiträge: 6
Registriert: Freitag 24. Oktober 2008, 08:41

Wie kommst du auf <del>?
Aus der Python 2.6 Onlinehilfe:
exception KeyboardInterrupt
Raised when the user hits the interrupt key (normally Control-C or Delete).
Habe bisher werder von ncurses noch urwid gehört ... habe mir beides bisher nur kurz angesehen. Danke zumindest für den Hinweis. Ich verstehe nur nicht ganz, wieso so etwas (GotoXY) nicht mehr mit der Eingabeaufforderung möglich sein soll.
Die einzige Erklärung die ich mir zur Zeit geben könnte ist, dass DOS damals noch andere Funktionalitäten zur Verfügung stellte, die SO heute durch den neuen Windows Kernel (was auch immer) in der DOS-Box nicht mehr unterstützt werden.
Mir fehlt wahrscheinlich noch das grundlegende Verständnis wie das damals überhaupt funktionierte. ncurses und urwid sind ja wohl sowas wie Terminal Programme ... die DOS-Box ja auch (!?). So gesehen könnte ich verstehen, dass diese Programme eine unterschiedliche Funktionsweise zur Verfügung stellen. Die DOS-Box hat für mich auf jeden Fall den Vorteil, dass sie standardmäßig vorhanden ist.
Würde mich freuen, falls Du (oder jemand anders) da mein Konzeptverständnis ergänzen/korrigieren könntest!?
BlackJack

Zu DOS-Zeiten haben Programme die BIOS-Funktionen für den Textbildschirm aufgerufen und/oder direkt im Bildschirmspeicher herum geschrieben, der an einer absoluten Speicheradresse zu finden war. Das ist beides bei plattformunabhängigen Mehrbenutzersystemen nicht mehr drin.

Ansonsten kann man "echten" Terminals Steuercodes schicken, zum Beispiel vielen ANSI-Escape-Codes. Das geht bei DOS auch, wenn man den ANSI.SYS-Treiber lädt. Was Microsoft dummerweise bei Windows nicht standardmässig macht. Und das heute noch Leute wissen was eine AUTOEXEC.BAT ist und wie man da den Treiber lädt, ist eher unwahrscheinlich.
Poisos
User
Beiträge: 6
Registriert: Freitag 24. Oktober 2008, 08:41

Ah ja ... so eine archaische Methode hatte ich erwartet. (Die guten alten einfachen Zeiten :D.) Ich weiß zwar noch was die AUTOEXEC.BAT ist aber bis auf das Herumspielen mit HIMEM um mir irgendwie mehr Speicher für das ein oder andere Spiel zu beschaffen hab' ich nicht wirlich viel damit gemacht, geschweige denn verstanden, wozu das Ding sonst noch nützlich war.
'Ne ansi.sys gibt 's ja noch. Werd' mal schauen ob ich diese Richtung noch mal weiter untersuche - just for the pleasure of knowledge.
Für mich jedenfalls ein interessanter Hinweis, danke!
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Ein `goto(x, y)` erscheint mir schon deshalb als bedenklicher Ansatz, weil Terminals heutzutage sehr unterschiedliche Größen haben können. Entweder beschränkt man die Ausgabe also auf einen festen Bereich (etwa 80x25) oder muss sehr flexibel programmieren, um jede Größe auszunutzen.
lunar

Y0Gi hat geschrieben:Ein `goto(x, y)` erscheint mir schon deshalb als bedenklicher Ansatz, weil Terminals heutzutage sehr unterschiedliche Größen haben können. Entweder beschränkt man die Ausgabe also auf einen festen Bereich (etwa 80x25) oder muss sehr flexibel programmieren, um jede Größe auszunutzen.
Wieso? Man muss halt vorher nur die Breite des Terminals in Erfahrung bringen ... nichts anderes tut curses doch.

@BlackJack
Werten moderne Windows-Systeme die autoexec.bat überhaupt noch aus? Iirc ist das seit XP alles in der Registry zu finden...
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

lunar hat geschrieben:Werten moderne Windows-Systeme die autoexec.bat überhaupt noch aus? Iirc ist das seit XP alles in der Registry zu finden...
Ich meine gehört zu haben, dass bestimmte Befehle verstanden werden (%PATH% setzen etwa), aber sonst steht in der autoexec.bat ja kaum was, was für ein NT-System von irgendeiner bedeutung wäre. Daher habe ich die immer gelöscht.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

lunar hat geschrieben:Wieso? Man muss halt vorher nur die Breite des Terminals in Erfahrung bringen ... nichts anderes tut curses doch.
Schon. Man kann nur eben von keiner festen Größe ausgehen, wie es damals vielleicht der Fall war.


In der `AUTOEXEC.BAT` habe ich unter XP für das meiste den Pfad gesetzt, ansonsten fällt mir auch kein Zweck mehr ein.
BlackJack

@Y0Gi: Ich denke man kann in der Regel von 80x24 Minimum ausgehen, bzw. von 80x25 bei DOS und Nachfolgern. Und fest war die Grösse damals auch schon nicht, ich hatte meistens 132x50 Zeichen eingestellt.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Jou, denn man zu.

Um wieder etwas zum Kern zurück zu kommen: Für 'nen einfachen Statusbalken im Konsolenstil (also nicht sowas wie z. B. bei blau-grauen DOS-Installern) reicht ein bisschen ASCII-Steuerzeichen-Geschubse (s. meine Codebeispiele) allemal. Den Einsatz von sowas wie ncurses sollte man an anderen Kriterien fest machen ;)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Y0Gi hat geschrieben:Den Einsatz von sowas wie ncurses sollte man an anderen Kriterien fest machen ;)
Du meinst "Schmerzresistenz", hmm? ;)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

*Eigentlich* dachte ich mehr an sowas wie "ich will GUI-Kram auf der Konsole machen, also nicht rein zeilenbasiert, sondern mit Widgets und so". In dem Sektor habe ich allerdings keine Erfahrung als Entwickler, sondern nur als Anwender (irssi, cmus, rtorrent etc.).
lunar

Das geht allerdings über reines curses hinaus. curses an sich ist ja kaum mehr als ein Wrapper um die Zeichenfähigkeiten von VT100-Terminals.

Um solche UIs zu erstellen, braucht es dann Toolkits wie urwid.
Antworten