Cat-Datei zum Terminal mit einer bestimmten Geschwindigkeit von Zeilen pro Sekunde

14

Ich bin faul und könnte ein Skript schreiben, um dies zu tun, aber ich bin sogar zu faul, um darüber nachzudenken, wie es geht.

Ich mache oft Dinge wie:

cris$ python runexperiment.py > output.txt
cris$ cat output.txt

Manchmal, wenn ich mir die lange Ausgabe eines Experiments anschaue, lasse ich die Seite einfach scrollen und beobachte, wie sich die aufeinanderfolgenden Muster bilden und zerstreuen. Die Verwendung von cat für eine Datei mit 1 Million Zeilen dauert jedoch möglicherweise 5 Sekunden. Das ist selbst für mich zu schnell.

Gibt es eine Möglichkeit, die Anzeige der Datei zu verlangsamen, so etwas wie ein "Bildlauf-Dienstprogramm"? Ich möchte schnelle, aber nicht 200.000 Zeilen pro Sekunde (von denen sich das Display vermutlich sowieso nie registrieren würde).

Etwas wie

cris$ scroll -lps=300 output.txt

Und dann wäre es ideal, sich zurückzulehnen und 300 Zeilen pro Sekunde vorbeiziehen zu sehen, wie ich mir vorstellen kann.

Cris Stringfellow
quelle
7
Versuchen Sie etwas wie cat FILENAME | pv -l -L 900 -q. Die Grenze liegt in Bytes pro Sekunde, nicht in Zeilen pro Sekunde, daher mache ich dies zu einem Kommentar und nicht zu einer Antwort.
David Schwartz
Ok, das ist ein cooles Dienstprogramm, und das funktioniert teilweise. Aber ja, es ist ein wenig abgehackt, da es nach bps geht, nicht nach lps.
Cris Stringfellow

Antworten:

17

Kurz und lesbar :

perl -pe "system 'sleep .003'" log.txt

Ich poste diese Lösungen, weil sie klein und lesbar sind, da Kommentare der Antwort von DMas diese Art von Lösung zu fördern scheinen!

Aber ich hasse es , weil: Für diesen Lauf, perl wird Gabel zu /bin/sleep300x / Sekunden!

Dies ist ein großer Ressourcenverbraucher! Auch eine falsche gute Lösung !!

Mit eingebautem Schlaf in

Leider ist Builtin sleepauf ganze Zahlen beschränkt. Also müssen wir selectstattdessen verwenden:

perl -e 'print && select undef,undef,undef,.00333 while <>;'

Unter Perl print while <>könnte durch den -pSchalter ersetzt werden:

perl -pe 'select undef,undef,undef,.00333'

Lass es uns versuchen:

time /bin/ls -l /usr/bin | perl -pe 'select undef,undef,undef,.00333' | wc
   2667   24902  171131

real    0m9.173s
user    0m0.056s
sys     0m0.048s

bc -l < <(echo 2667/9.173)
290.74457647443584432573

Erläuterung:

  • 300 Zeilen / Sek. Bedeutet 1 Zeile pro 0,0033333333 Sekunden.

  • printohne Argument wird gedruckt, $_was der Standardeingabebereich ist .

  • genannt , wie ... | perl -e, ... | perl -neoder ... | perl -pewürde die Standardeingabe automatisch zugewiesen werden , *STDINwas Standard Dateideskriptor , also <>das gleiche tun würde , wie <STDIN>die von der Standardeingabe bis gelesen wird $/( Eingangsdatensatztrennzeichen, das eine standardmäßig ist Neue - Zeile ) erreicht wird. In Englisch wird standardmäßig eine Zeile aus der Standardeingabe <>gelesen und der Variablen Inhalt zugewiesen .$_

  • &&ist eine und -Bedingung, wird dort jedoch als Trennzeichen für Kettenbefehle verwendet, sodass nach (erfolgreichem) Drucken einer Zeile der nächste Befehl ausgeführt wird.

  • selectist ein Tricksleep eines Programmierers, den man nicht benutzt . Dieser Befehl dient zum Abfangen von Ereignissen in Dateideskriptoren (Ein- und / oder Ausgänge, Dateien, Sockets und / oder Net-Sockets). Mit diesem Befehl kann ein Programm auf drei Arten von Ereignissen warten : Feed bereit zum Lesen , Feed bereit zum Schreiben und ein Ereignis ist im Feed aufgetreten . Das vierte Argument ist eine Zeitüberschreitung in Sekunden, die Syntax also select <feeds where wait for input>, <feeds where having to write>, <feed where something could happen>, <timeout>.

Für mehr Präzision können Sie das Time::HiresPerl-Modul verwenden:

perl -MTime::HiRes -pe 'BEGIN{$start=Time::HiRes::time;$sleepPerLine=1/300};select undef,undef,undef,($start + $sleepPerLine*$. - Time::HiRes::time)'

Hinweis: $.ist die aktuelle Eingabezeilennummer .

Besser geschrieben als cat >catLps.pl

#!/usr/bin/perl -w

use strict;
use Time::HiRes qw|time|;

my $start=time;
my $lps=300;

$lps=shift @ARGV if @ARGV && $ARGV[0]=~/^(\d+)$/;
my $sleepPerLine=1/$lps;

print &&
    select undef,undef,undef,($start + $sleepPerLine*$. - Time::HiRes::time)
    while <>

Verwendung:

catLps.pl [lps] [file] [file]...

Das erste Argument lpsist ein optionales numerisches Argument für Zeile pro Sekunde (Standard: 300).

Hinweis: Wenn der Dateiname nur numerisch ist, müssen Sie ihn möglicherweise mit dem folgenden Pfad angeben : ./3.

Auf catdiese Weise könnten Dateien übergeben werden, die als Argument und / oder Standardeingabe angegeben wurden

So konnten wir:

TIMEFORMAT='%R' 
time seq 1 100 | ./catLps.pl 100 >/dev/null 
1.040

time seq 1 10000 | ./catLps.pl 10000 >/dev/null  
1.042

Zum Spass:

export TIMEFORMAT='%R' ;clear ;time seq 1 $((LINES-2)) | ./catLps.pl $((LINES-2))
F. Hauri
quelle
2
das sieht aus wie ein ernstes Voodoo, das du dort machst. das ist so cool, ich habe es versucht und es funktioniert. Ich habe keine Ahnung, wie du das gemacht hast. Was zum Teufel ist Perl Select? undef? Ich kann es nachschlagen. tolle.
Cris Stringfellow
2
@CrisStringfellow Ok, ich habe einige Erklärungen und ein vollständiges Skript mit Time::HiResPerl-Modul für mehr Genauigkeit hinzugefügt
F. Hauri
mein Gott. Das ist eine großartige Antwort. Vielen Dank. Ich habe ein zweites Mal versucht, es zu verbessern. Ich lerne etwas, indem ich Ihre wunderbare Erklärung lese.
Cris Stringfellow
2
Sie könnten auch meine Kommentare positiv bewerten ;-)
F. Hauri
@CrisStringfellow Antwort bearbeitet: Durch die Verwendung des -pBefehls zum Perl wechseln wurde das Skript erleichtert!
F. Hauri
11

benutze einfach awk mit schlaf:

awk '{print $0; system("sleep .1");}' log.txt
DMas
quelle
Dies funktionierte für mich und für meine Situation war dies die beste Option und nicht die oben genannten Skriptoptionen. Unsicher, warum diese Antwort abgelehnt wird.
Bürger Kepler
2
Im Gegensatz zur Perl-Lösung ist es gut lesbar.
Revolverheld
1
@ Gunslinger: Syntax system(*sleep .1")generiert 10 Gabeln / Sek.! Dies könnte geschrieben werden perl -pe 'system "sleep .1"' log.txt: Lesbar auch, aber sehr teuer (nicht systemfreundlich!)
F. Hauri
Auch ich bevorzuge diese lesbare Antwort. Das einzige ist, dass der Shell-Schlafbefehl für jede ausgegebene Zeile ausgelöst wird. Aber es ist mir egal, ob ich ein perfekt lesbarer Einzeiler bin.
Feuer
0

Ich bin zu spät zur Party, aber ich fand, dass dies eine nützliche Lernübung wäre, um es in Python zu versuchen, also werde ich aufstellen, was ich habe:

#!/usr/bin/env python3

import argparse
from time import sleep

parser = argparse.ArgumentParser(description='Echo a file slowly')
parser.add_argument('-i',
                    '--input-file',
                    type=argparse.FileType('r'),
                    default='-')
parser.add_argument('-d',
                    '--delay-in-ms',
                    type=int,
                    default='100')
args = parser.parse_args()

for line in args.input_file:
    print(line.rstrip())
    sleep(args.delay_in_ms/1000.0)

Es akzeptiert Eingaben von stdin oder als Argument (-i) und schreibt standardmäßig eine Zeile pro 1/10 Sekunde, dies kann jedoch durch ein anderes Argument (-d) geändert werden.

Grezzo
quelle
Vielen Dank. Ich fing an, etwas Ähnliches wie diese Idee in Python zu entwickeln, als ich auf diese Fragen und Antworten stieß. Ich stelle fest, dass Python auch select docs.python.org/3/library/select.html unterstützt, ähnlich wie Perl, wie es in der Antwort von F. Hauri verwendet wird.
ybull