Fichier Cat vers le terminal à une vitesse particulière de lignes par seconde

15

Je suis paresseux et je pourrais écrire un script pour le faire, mais je suis même trop paresseux pour penser à comment le faire.

Je fais souvent des choses comme:

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

Parfois, en regardant le long résultat d'une expérience, j'aime laisser la page défiler et regarder les modèles successifs se former et se disperser. Mais l'utilisation de cat sur un fichier avec 1 million de lignes se termine en peut-être 5 secondes. C'est trop rapide, même pour moi.

Existe-t-il un moyen de ralentir la vitesse d'affichage du fichier, quelque chose comme un «utilitaire de défilement»? Je veux rapide, mais pas 200k lignes par seconde (tout cela sans doute que l'écran ne s'enregistrerait même pas de toute façon).

Quelque chose comme

cris$ scroll -lps=300 output.txt

Et puis s'asseoir et regarder 300 lignes par seconde passer serait idéal, j'imagine.

Cris Stringfellow
la source
7
Essayez quelque chose comme cat FILENAME | pv -l -L 900 -q. La limite est en octets par seconde, pas en lignes par seconde, donc j'en fais un commentaire et non une réponse.
David Schwartz
D'accord, c'est un utilitaire sympa, et cela fonctionne en partie. Mais oui, c'est un peu saccadé car ça va après les bps pas les lps.
Cris Stringfellow

Réponses:

17

Court et lisible :

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

Je poste ces solutions car elles sont petites et lisibles, car les commentaires de la réponse de DMas semblent promouvoir ce type de solution!

Mais je déteste ça parce que: pour cette course, perl va bifurquer à /bin/sleep300x / secondes!

C'est un gros consommateur de ressources! Aussi une mauvaise bonne solution !!

Utilisation du sommeil intégré en

Malheureusement, la fonction intégrée sleepest limitée aux nombres entiers. Nous devons donc utiliser à la selectplace:

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

Sous perl, print while <>pourrait être remplacé par le -pswitch:

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

Essayons:

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

Explication:

  • 300 lignes / s signifie 1 ligne par 0,0033333333 s.

  • printsans argument imprime $_qui est l'espace d'entrée par défaut .

  • appelé comme ... | perl -e, ... | perl -neou ... | perl -pe, l'entrée standard serait automatiquement affectée à *STDINquel est le descripteur de fichier par défaut , <>ferait de même que celui <STDIN>qui lira à partir de l'entrée standard jusqu'à ce que $/( séparateur d'enregistrement d'entrée qui est par défaut une nouvelle ligne ) soit atteint. En anglais, par défaut <>, lira une ligne de l'entrée standard et attribuera le contenu à la $_variable.

  • &&est une condition et , mais y est utilisé comme séparateur de commande de chaîne, donc après (avec succès) imprimer une ligne, en exécutant la commande suivante.

  • selectest une astuce de programmeur à ne pas utilisersleep . Cette commande est conçue pour intercepter les événements sur les descripteurs de fichiers (entrées et / ou sorties, fichiers, socket et / ou net sockets). Avec cette commande, un programme peut attendre 3 types d'événements, un flux prêt à lire , un flux prêt à écrire et un événement s'est produit sur le flux . Le quatrième argument est un délai d'expiration en secondes, la syntaxe l'est donc select <feeds where wait for input>, <feeds where having to write>, <feed where something could happen>, <timeout>.

Pour plus de précision, vous pouvez utiliser le Time::Hiresmodule perl:

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

Remarque: $.est le numéro de ligne d'entrée actuel .

Mieux écrit comme 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 <>

Usage:

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

Le premier argument lpsest un argument numérique optionnel de ligne par seconde (par défaut: 300)

Remarque: si le nom de fichier est uniquement numérique, vous pouvez avoir les specifiy avec le chemin: ./3.

Comme catcela pourrait passer des fichiers donnés comme argument et / ou entrée standard

Nous pourrions donc:

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

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

Pour s'amuser:

export TIMEFORMAT='%R' ;clear ;time seq 1 $((LINES-2)) | ./catLps.pl $((LINES-2))
F. Hauri
la source
2
qui ressemble à un vaudou sérieux que vous faites là-bas. c'est tellement cool, je l'ai essayé et ça marche. je ne sais pas comment tu as fait ça. que diable est perl select? undef? je peux le rechercher. incroyable.
Cris Stringfellow
2
@CrisStringfellow Ok, j'ai ajouté quelques explications et un script complet en utilisant le Time::HiResmodule perl pour plus de précision
F. Hauri
mon Dieu. C'est une réponse géniale. Je vous remercie. J'ai essayé de le voter une deuxième fois. J'apprends quelque chose en lisant votre merveilleuse explication.
Cris Stringfellow
2
Vous pouvez aussi voter sur mes commentaires ;-)
F. Hauri
@CrisStringfellow Réponse éditée: en utilisant la -pcommande switch to perl, le script a été allégé!
F.Hauri
11

utilisez simplement awk avec sommeil:

awk '{print $0; system("sleep .1");}' log.txt
DMas
la source
Cela a fonctionné pour moi et pour ma situation était la meilleure option plutôt que les options de script ci-dessus. Je ne sais pas pourquoi cette réponse est rejetée.
Citizen Kepler
2
Contrairement à la solution Perl, elle est assez lisible.
Gunslinger
1
@Gunslinger: La syntaxe system(*sleep .1")générera 10 fourchettes / secondes! Cela pourrait être écrit perl -pe 'system "sleep .1"' log.txt: lisible aussi, mais très cher (pas compatible avec le système!)
F. Hauri
Moi aussi, je préfère cette réponse lisible. La seule chose est qu'il déclenchera la commande shell sleep pour chaque ligne qu'il sort. Mais étant une doublure parfaitement lisible, je m'en fiche.
itsafire
0

Je suis en retard à la fête, mais j'ai trouvé que ce serait un exercice d'apprentissage utile pour essayer en python, donc je vais mettre en place ce que j'ai obtenu:

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

Il accepte les entrées de stdin ou comme argument (-i) et écrit par défaut une ligne par 1 / 10ème de seconde, mais cela peut être modifié avec un autre argument (-d).

Grezzo
la source
Merci. Je commençais à développer quelque chose de similaire à cette idée en Python lorsque je suis tombé sur cette Q & Ad. Je note que Python prend également en charge certains docs.python.org/3/library/select.html d'une manière similaire à Perl comme utilisé dans la réponse de F. Hauri.
ybull