Seite 1 von 1
Konsole: Busy-Anzeige
Verfasst: Mittwoch 26. April 2006, 14:10
von droptix
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?
Verfasst: Mittwoch 26. April 2006, 14:24
von CM
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
Verfasst: Mittwoch 26. April 2006, 14:25
von Rebecca
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!
Verfasst: Mittwoch 26. April 2006, 14:26
von icepacker
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.
Verfasst: Mittwoch 26. April 2006, 14:31
von jens
Verfasst: Mittwoch 26. April 2006, 14:53
von droptix
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...
Verfasst: Mittwoch 26. April 2006, 15:21
von Rebecca
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)...
Mein Beispiel das nicht geht
Verfasst: Mittwoch 26. April 2006, 15:34
von droptix
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...
Stimmt nicht ganz
Verfasst: Mittwoch 26. April 2006, 15:37
von droptix
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).
Verfasst: Mittwoch 26. April 2006, 17:25
von CM
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

.
Gruß,
Christian
Schon gemacht
Verfasst: Mittwoch 26. April 2006, 19:00
von droptix
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

Re: Schon gemacht
Verfasst: Donnerstag 27. April 2006, 08:32
von CM
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
Ich gestehe...
Verfasst: Donnerstag 27. April 2006, 11:15
von droptix
Und ich gestehe, dass ich das ganz clever auch mit Leerzeichen löse, nämlich so
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)
Re: Ich gestehe...
Verfasst: Donnerstag 27. April 2006, 14:21
von Joghurt
Ein
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.
Re: Stimmt nicht ganz
Verfasst: Dienstag 2. Mai 2006, 13:06
von Leonidas
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.
Verfasst: Dienstag 2. Mai 2006, 14:15
von Joghurt
WTF is DPU?
Edit: Ah! Daily Python URL
Verfasst: Dienstag 2. Mai 2006, 14:19
von Leonidas
Joghurt hat geschrieben:Edit: Ah! Daily Python URL
Jup, genau. Damit hätten wir auch einen Post der erklärt was DPU ist. Die Suchfunktion wirds freuen, wenns mal jemanden interessiert. Nur die für die Suchfunktion interessiert sich kaum einer.