Konsole: Busy-Anzeige

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.
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Mittwoch 26. April 2006, 14:10

Ich bearbeite in der Konsole nacheinander viele Dateien. Wenn ich während dieser Zeit nix ausgebe, könnte man (bei einer leisen Festplatte) auch meinen, das Programm sei abgestürzt.

Ich will dem Anwender also verdeutlichen, welche Datei gerade bearbeitet wird. Eine Ausgabe mit print erzeugt eine unübersichtlich lange Ausgabe. Ich hätte es gern, dass nur auf einer Zeile der aktuelle Dateiname ausgegeben wird. Die nächste Datei wird dann also über den Platz der ersten geschrieben. Somit wird immer nur eine Zeile "verschwendet" und man weiß aber, das das Programm beschäftigt ist.

Wie realisiert man das? Mit print komme ich nicht weiter. Hab mir sys.stdout.write() angesehen, aber da hab ich auch nix zum "überschreiben" entdeckt. Geht das überhaupt?
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Mittwoch 26. April 2006, 14:24

Code: Alles auswählen

sys.stdout.write('Working on ... %s  \r' % fname)
sys.stdout.flush()
ist wie ich das manchmal löse, ggf. auch in eine Extra-Funktion verpackt.

Dich interessiert vielleicht noch eine Liste von Escape-Charaktären:

\e Write an <escape> character.
\a Write a <bell> character.
\b Write a <backspace> character.
\f Write a <form-feed> character.
\n Write a <new-line> character.
\r Write a <carriage return> character.
\t Write a <tab> character.
\v Write a <vertical tab> character.
\' Write a <single quote> character.
\\ Write a backslash character.
\num Write an 8-bit character whose ASCII value is the 1-, 2-, or 3-digit octal number num.

Solche Listen sind für jede Shell / Konsole leicht zu "ergoogeln" und - von leichten Variationen - stets recht ähnlich.

Gruß,
Christian
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Mittwoch 26. April 2006, 14:25

Carriage return (\r) setzt den Cursor an den Anfang der Zeile:

Code: Alles auswählen

#!/usr/bin/env python

import sys
import time

sys.stdout.write("Hallo Welt!")
sys.stdout.flush()
time.sleep(1)
sys.stdout.write("\rWas anderes...")
sys.stdout.flush()
time.sleep(1)
sys.stdout.write("\n")
EDIT: Da war wer schneller!
icepacker
User
Beiträge: 49
Registriert: Dienstag 15. November 2005, 18:48

Mittwoch 26. April 2006, 14:26

Hi
Doch sollte mit print gehen.
Schau dir mal carriage return ( "\r" ) an!

lg icepacker

edit: Na klasse :?
10 Minuten antwortet keiner und dann auf einmal 3 Leute fast zeitgleich.
ubuntu linux !!
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 26. April 2006, 14:31


CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Mittwoch 26. April 2006, 14:53

Rebecca hat geschrieben:Carriage return (\r) setzt den Cursor an den Anfang der Zeile:

Code: Alles auswählen

import sys
import time
sys.stdout.write("Hallo Welt!")
sys.stdout.flush()
time.sleep(1)
sys.stdout.write("\rWas anderes...")
sys.stdout.flush()
time.sleep(1)
sys.stdout.write("\n")
Hmmm. Das funzt bei mir, aber meine Version geht nicht... Ich versuch das mal auf ein paar Zeilen runter zu brechen... kommt gleich.

P.S. Was macht das 'flush()'?

Hmm, das is ja seltsam. Wenn ich immer nur einen konstanten Wert mit write() schreibe, also z.B. write("\r%s" % "..."), dann geht's. Aber wenn ich meinen Dateinamen reinschreibe, also write("\r%s" % filePath), dann erscheinen weiterhin alle untereinander, so als würde ich print benutzen...
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Mittwoch 26. April 2006, 15:21

droptix hat geschrieben: P.S. Was macht das 'flush()'?
stdout ist gepuffert (Filedescriptor!), ohne flush kriegt man die Ausgabe nicht sofort auf den Bildschrim geschrieben, sondern wenn der Buffer voll ist.
droptix hat geschrieben:Hmm, das is ja seltsam. Wenn ich immer nur einen konstanten Wert mit write() schreibe, also z.B. write("\r%s" % "..."), dann geht's. Aber wenn ich meinen Dateinamen reinschreibe, also write("\r%s" % filePath), dann erscheinen weiterhin alle untereinander, so als würde ich print benutzen...
Vielleicht hat der Inhalt von filePath noch ein \n am Ende? Mach mal repr(filePath)...
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Mittwoch 26. April 2006, 15:34

Das geht nicht: Ich übergebe an das Script einen Pfad im Dateisystem. Den hab ich jetzt mal künstlich festgelegt:

Code: Alles auswählen

import sys, os, time

sys.argv.append(r"C:\Dokumente und Einstellungen\All Users\Dokumente")

if sys.argv[1]:
    for path, dirs, files in os.walk(sys.argv[1]):
        for file in files:
            uri = os.path.join(path, file)
            # busy...
            sys.stdout.write("\r%s" % uri)
            sys.stdout.flush()
            time.sleep(0.01)
So bekomme ich alle Dateinamen untereinander. Das mit dem "\n" am Anfang oder Ende hatte ich auch schon überlegt und überprüft per:

Code: Alles auswählen

if uri.startswith("\n") or uri.endswith("\n"):
    print "shit"
Aber "shit" kam nie. Also hab ich mal nicht den Dateinamen, sondern eine Konstante ausgegeben. Komischweise kommt das nicht untereinander:

Code: Alles auswählen

import sys, os, time

sys.argv.append(r"C:\Dokumente und Einstellungen\All Users\Dokumente")

if sys.argv[1]:
    for path, dirs, files in os.walk(sys.argv[1]):
        for file in files:
            uri = os.path.join(path, file)
            # busy...
            sys.stdout.write("\r%s" % "...")
            sys.stdout.flush()
            time.sleep(0.01)
Also muss es am Dateiname uri liegen...
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Mittwoch 26. April 2006, 15:37

repr(uri) ergibt gar nichts. Ich hab mal den Sleep-Timer erhöht und konnte feststellen, dass doch in einigen Zeilen der Dateiname überschrieben wird. Bei anderen wiederum wird mit einer neuen Zeile begonnen. Seltsam.

[edit] Aaaaaaaaaaaah. Wenn der Dateiname sooo lang ist, dass er nciht auf eine Zeile in der Konsole passt, dann wird natürlich ein automatischer Umbruch erzeugt. Dummerweise wird dann nur der Bereich der zweiten (bzw. letzten) Zeile mittels "\r" überschrieben. Also muss ich die Ausgabe auf z.B. 79 Zeichen begrenzen...

Kann ich die Breite der Konsole auslesen, damit ich diese statische Zahl 79 umgehen kann? Eigentlich ist die Standard-Windows-Konsole 80 Zeichen breit, aber die kann man ja verbreitern (wie unter Unixen auch).
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Mittwoch 26. April 2006, 17:25

Womöglich schon - kenne mich mit Windows nicht so aus - aber glaube mir: Das willst Du nicht!

Es ist - meiner bescheidenen Erfahrung und meiner unmaßgeblichen Meinung nach - besser derartige Pfadangaben einzukürzen (z. B. nur den eigentlichen Dateinahmen zu nehmen oder best. Ordner durch ... zu ersetzen). Auf diese Weise ist eine solche Ausgabe lesbarer und nachvollziebar. Wenn ewig lange Zeilen über den Schirm huschen sieht das zwar für Deine Kollegen so aus, als würdest Du ganz doll und viel arbeiten, aber hilft doch eigentlich nicht weiter :wink: .

Gruß,
Christian
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Mittwoch 26. April 2006, 19:00

Sehr lustig... denn genau das hatte ich heute Nachmittag bereits gemacht :) Also die Dateinamen für die Ausgabe eingestampft. Schon erledigt quasi.

Was mir auch noch aufgefallen ist: ein carriage return setzt ja wirklich nur den Cursor auf die Anfangszeile, löscht diese aber nicht. Also muss ich "alte Reste" der vorherigen Ausgabe fein mit Leerzeichen überschreiben. Oder kann man die Zeile auch komplett leeren?
CM hat geschrieben:Womöglich schon - kenne mich mit Windows nicht so aus - aber glaube mir: Das willst Du nicht!
Was meinst du damit? Das ist bei Unixen mit langen Pfaden doch genau dasselbe... Das Python-Tool ist eh ein Multiplattform-Tool :)
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Donnerstag 27. April 2006, 08:32

Moin,
droptix hat geschrieben:Was meinst du damit?
damit meine ich, daß der Aufwand nicht das Ergebnis rechtfertigt und Du nicht glücklich mit den vergrößerten Konsolenfenstern sein wird. Na gut, da kann ich mich irren und das Ausrufezeichen war sicher überflüssig ...

Bzgl. \r: Du kannst entweder Leerzeichen nehmen oder 'x * \b' einsetzen. Beides dirty hacks, aber ich weiß nichts besseres - jemand mit einer besseren Idee? (Ich gebe frei zu meist einfach ein paar Leerzeichen an die Ausgabe, s.o., zu hängen ...)

Gruß,
Christian
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Donnerstag 27. April 2006, 11:15

Und ich gestehe, dass ich das ganz clever auch mit Leerzeichen löse, nämlich so :D

Code: Alles auswählen

# quick 'n' dirty
import sys, string, time

maxlen = 30
abbrev = "..."
abslen = maxlen - len(abbrev)

def p(m):
    global maxlen, abbrev, abslen
    if len(m) > maxlen:
        m = string.join([m[:abslen], abbrev], "")
    sys.stdout.write("\r%s\r%s" % (maxlen * " ", m))
    sys.stdout.flush()

p("Hello world it's python!")
time.sleep(1)
p("I'm really great!")
time.sleep(1)
p("Believe me!")
time.sleep(1)
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Donnerstag 27. April 2006, 14:21

droptix hat geschrieben:

Code: Alles auswählen

sys.stdout.write("\r%s\r%s" % (maxlen * " ", m))
Ein

Code: Alles auswählen

sys.stdout.write("\r%*s" % (-maxlen, m))
tut's auch.

(Für konstante maxlen von 60 geht z.B. auch "\r%-60s" % m)

Noch ein Hinweis: Wenn die bearbeitung pro Datei nicht lange dauert, ist es besser, nicht jede Datei einzeln anzuzeigen. Ansonsten verbringt das Programm mehr mit dem Anzeigen der Dateinamen als mit der eigentlichen Aufgabe.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 2. Mai 2006, 13:06

droptix hat geschrieben:Kann ich die Breite der Konsole auslesen, damit ich diese statische Zahl 79 umgehen kann? Eigentlich ist die Standard-Windows-Konsole 80 Zeichen breit, aber die kann man ja verbreitern (wie unter Unixen auch).
Ich weiß, dass es etwas spät ist, aber besser spät als nie: Ein Rezept, heute per DPU gefunden.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Antworten