Plik cat do terminala z określoną prędkością linii na sekundę

15

Jestem leniwy i mógłbym napisać skrypt, aby to zrobić, ale jestem zbyt leniwy, aby wymyślić, jak to zrobić.

Często robię takie rzeczy jak:

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

Czasami, patrząc na długi wynik eksperymentu, lubię pozwalać stronie przewijać się i patrzeć, jak kolejne wzorce tworzą się i rozpraszają. Ale użycie cat na pliku z 1 milionem linii kończy się może w 5 sekund. To jest zbyt szybkie nawet dla mnie.

Czy jest jakiś sposób na spowolnienie przeglądania pliku, coś w rodzaju „narzędzia do przewijania”? Chcę szybko, ale nie 200 000 wierszy na sekundę (z których wszystkie prawdopodobnie i tak nigdy się nie zarejestrują).

Coś jak

cris$ scroll -lps=300 output.txt

A potem wyobrażam sobie, że siedzenie i oglądanie 300 linii na sekundę jest idealne.

Cris Stringfellow
źródło
7
Spróbuj czegoś takiego cat FILENAME | pv -l -L 900 -q. Limit jest w bajtach na sekundę, a nie liniach na sekundę, więc robię z tego komentarz, a nie odpowiedź.
David Schwartz
Dobra, to fajne narzędzie, które działa częściowo. Ale tak, to jest trochę niepewne, ponieważ idzie po bps, a nie lps.
Cris Stringfellow,

Odpowiedzi:

17

Krótki i czytelny :

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

Publikuję te rozwiązania, ponieważ są one małe i czytelne, ponieważ komentarze do odpowiedzi DMas wydają się promować takie rozwiązanie!

Ale nienawidzę tego powodu: W tym okresie, Perl będzie bulić do /bin/sleep300x / sek!

To duży konsument zasobów! Również złe dobre rozwiązania !!

Korzystanie z wbudowanego trybu uśpienia w

Niestety, wbudowane sleepjest ograniczone do liczb całkowitych. selectZamiast tego musimy użyć :

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

W Perlu print while <>można zastąpić -pprzełącznikiem:

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

Spróbujmy:

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

Wyjaśnienie:

  • 300 linii / sek oznacza 1 linię o 0,0033333333 sek.

  • printbez argumentów, $_które są domyślną przestrzenią wejściową .

  • wywoływane jako ... | perl -e, ... | perl -nelub ... | perl -peautomatycznie zostanie przypisane standardowe wejście, do *STDINktórego jest domyślny deskryptor pliku , więc <>zrobi to samo, <STDIN>co odczytane ze standardowego wejścia, dopóki nie zostanie osiągnięty $/( separator rekordów wejściowych, który jest domyślnie nowy wiersz ). W języku angielskim domyślnie <>odczytuje jeden wiersz ze standardowego wejścia i przypisuje zawartość do $_zmiennej.

  • &&jest warunkiem i , ale jest tam stosowany jako separator poleceń łańcuchowych, więc po (pomyślnym) wydrukowaniu jednego wiersza i wykonaniu następnego polecenia.

  • selectto sztuczka programisty, której nie należy używaćsleep . To polecenie służy do przechwytywania zdarzeń na deskryptorach plików (wejścia i / lub wyjścia, pliki, gniazda i / lub gniazda sieciowe). Za pomocą tego polecenia program może czekać na 3 rodzaje zdarzeń, kanał gotowy do odczytu , kanał gotowy do zapisu i pewne zdarzenie wydarzyło się podczas kanału . Czwarty argument to limit czasu w sekundach, więc składnia jest select <feeds where wait for input>, <feeds where having to write>, <feed where something could happen>, <timeout>.

Dla większej precyzji możesz użyć Time::Hiresmodułu perl:

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

Uwaga: $.jest bieżącym numerem linii wejściowej .

Lepiej napisane jako 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 <>

Stosowanie:

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

Pierwszy argument lpsto opcjonalny argument liczbowy na sekundę (domyślnie: 300)

Uwaga: Jeśli nazwa pliku jest tylko numeryczny, być może trzeba będzie specifiy je ze ścieżką: ./3.

W catten sposób można przekazać pliki podane jako argument i / lub standardowe dane wejściowe

Abyśmy mogli:

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

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

Dla zabawy:

export TIMEFORMAT='%R' ;clear ;time seq 1 $((LINES-2)) | ./catLps.pl $((LINES-2))
F. Hauri
źródło
2
to wygląda na poważne voodoo, które tam robicie. to jest takie fajne, próbowałem i działa. nie mam pojęcia, jak to zrobiłeś. co do diabła jest perl wybierz? undef? mogę to sprawdzić. niesamowity.
Cris Stringfellow,
2
@ CrisStringfellow Ok, dodałem wyjaśnienia i pełny skrypt używający Time::HiResmodułu perl dla większej dokładności
F. Hauri
mój Boże. To niesamowita odpowiedź. Dziękuję Ci. Po raz drugi próbowałem głosować za tym. Uczę się czegoś, czytając twoje cudowne wyjaśnienie.
Cris Stringfellow,
2
Możesz również głosować za moimi komentarzami ;-)
F. Hauri
@CrisStringfellow Odpowiedź edytowana: za pomocą -pkomendy switch to perl skrypt został rozjaśniony!
F. Hauri
11

po prostu użyj awk ze snem:

awk '{print $0; system("sleep .1");}' log.txt
DMas
źródło
To działało dla mnie i dla mojej sytuacji była najlepszą opcją, a nie powyższymi opcjami skryptu. Nie jestem pewien, dlaczego ta odpowiedź została odrzucona.
Citizen Kepler,
2
W przeciwieństwie do rozwiązania Perla jest dość czytelny.
Gunslinger,
1
@Gunslinger: Składnia system(*sleep .1")wygeneruje 10 rozwidleń / s! Można to napisać perl -pe 'system "sleep .1"' log.txt: też czytelne, ale bardzo drogie (nie przyjazne dla systemu!)
F. Hauri
Ja też wolę tę czytelną odpowiedź. Jedyną rzeczą jest to, że uruchomi polecenie uśpienia powłoki dla każdej linii, którą wysyła. Ale to, że jest to jedna czytelna wkładka, nie obchodzi mnie to.
itsafire
0

Spóźniłem się na przyjęcie, ale uznałem, że byłoby to przydatne ćwiczenie do nauki w Pythonie, więc przygotuję to, co mam:

#!/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)

Akceptuje dane wejściowe ze stdin lub jako argument (-i) i domyślnie zapisuje jedną linię na 1/10 sekundy, ale można to zmienić za pomocą innego argumentu (-d).

Grezzo
źródło
Dzięki. Zacząłem opracowywać coś podobnego do tego pomysłu w Pythonie, kiedy natrafiłem na te pytania i reklamy. Zwracam uwagę, że Python obsługuje również wybrane docs.python.org/3/library/select.html w podobny sposób jak Perl, jak użyto w odpowiedzi F. Hauri.
ybull