Arquivo Cat para o terminal a uma velocidade específica de linhas por segundo


15

Sou preguiçoso e poderia escrever um script para fazer isso, mas tenho preguiça de pensar em como fazê-lo.

Costumo fazer coisas como:

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

Às vezes, ao olhar para o longo resultado de um experimento, gosto de deixar a página rolar e observar os padrões sucessivos se formarem e se dispersarem. Mas usar gato em um arquivo com 1 milhão de linhas termina em talvez 5 segundos. Isso é rápido demais até para mim.

Existe alguma maneira de diminuir a velocidade da exibição do arquivo, algo como um 'utilitário de rolagem'? Eu quero rápido, mas não 200k linhas por segundo (todas presumivelmente a tela nunca seria registrada).

Algo como

cris$ scroll -lps=300 output.txt

E então, sentar e assistir 300 linhas por segundo rolar além seria o ideal, eu imagino.


7
Tente algo parecido cat FILENAME | pv -l -L 900 -q. O limite é em bytes por segundo, não em linhas por segundo, por isso estou fazendo disso um comentário, não uma resposta.
David Schwartz

Ok, bem, isso é um utilitário interessante e funciona em parte. Mas sim, é um pouco instável, pois vai depois de bps e não de lps.
precisa

Respostas:


17

Curto e legível :

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

Publico essas soluções porque são pequenas e legíveis, pois os comentários da resposta do DMas parecem promover esse tipo de solução!

Mas eu odeio isso porque: Para esta execução, o perl bifurcará para /bin/sleep300x / segundos!

Este é um grande consumidor de recursos! Também um boas soluções erradas !!

Usando o sono embutido em

Infelizmente, o builtin sleepé limitado a números inteiros. Então, temos que usar select:

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

Sob perl, print while <>pode ser substituído pelo -pswitch:

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

Vamos tentar:

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

Explicação:

  • 300 linhas / s significa 1 linha por 0,0033333333 segundos.

  • printsem argumento imprime $_qual é o espaço de entrada padrão .

  • chamado como ... | perl -e, ... | perl -neou ... | perl -pe, a entrada padrão será automaticamente atribuído ao *STDINque é descritor de arquivo padrão , de modo que <>faria o mesmo que <STDIN>que irá ler da entrada padrão até $/( separador de registro de entrada que é por padrão uma nova linha ) será alcançado. Em inglês, por padrão <>, lerá uma linha da entrada padrão e atribuirá o conteúdo à $_variável.

  • &&é um e condição, mas é usado lá como um separador de comando cadeia por isso depois (com sucesso) imprimir uma linha, fazendo próximo comando.

  • selecté o truque desleep um programador para não usar . Este comando foi projetado para interceptar eventos em descritores de arquivo (entradas e / ou saídas, arquivos, soquete e / ou soquetes de rede). Com esse comando, um programa pode aguardar 3 tipos de eventos, feed pronto para leitura , feed pronto para gravação e algum evento aconteceu no feed . O quarto argumento é um tempo limite em segundos, então a sintaxe é select <feeds where wait for input>, <feeds where having to write>, <feed where something could happen>, <timeout>.

Para mais precisão, você pode usar o Time::Hiresmódulo perl:

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

Nota: $.é o número da linha de entrada atual .

Melhor escrito como 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 <>

Uso:

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

O primeiro argumento lpsé o argumento numérico de linha por segundo opcional (padrão: 300)

Nota: se filename é de apenas numérico, você pode ter que especificar los com caminho: ./3.

Assim, catisso poderia passar arquivos fornecidos como argumento e / ou entrada padrão

Para que pudéssemos:

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

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

Para se divertir:

export TIMEFORMAT='%R' ;clear ;time seq 1 $((LINES-2)) | ./catLps.pl $((LINES-2))

2
parece um vodu sério que você está fazendo lá. isso é tão legal, eu tentei e funciona. Eu não tenho idéia de como você fez isso. que diabos é perl select? undef? Eu posso procurar. surpreendente.
precisa

2
@CrisStringfellow Ok, eu adicionei alguma explicação e um script completo usando Time::HiResmódulo perl para mais precisão
F. Hauri

meu Deus. Essa é uma resposta incrível. Obrigado. Eu tentei votar novamente pela segunda vez. Estou aprendendo algo lendo sua maravilhosa explicação.
precisa

2
Você poderia upvote meus comentários também ;-)
F. Hauri

@CrisStringfellow Resposta editada: pelo uso do -pcomando switch to perl, o script foi iluminado!
31716 F. Hauri

11

basta usar awk com sono:

awk '{print $0; system("sleep .1");}' log.txt

Isso funcionou para mim e para minha situação foi a melhor opção, e não as opções de script acima. Não sabe ao certo por que esta resposta está com voto negativo.
Citizen Kepler

2
Ao contrário da solução perl, é bastante legível.
Gunslinger

1
@ Gunslinger: Sintaxe system(*sleep .1")irá gerar 10 garfos / s! Isso poderia ser escrito perl -pe 'system "sleep .1"' log.txt: (! Não sistema amigável) legível também, mas muito caro
F. Hauri

Eu também prefiro essa resposta legível. A única coisa é que ele disparará o comando shell sleep para cada linha que ele emitir. Mas sendo uma linha perfeita e legível, não me importo.
itsafire

0

Estou atrasado para a festa, mas achei que seria um exercício de aprendizado útil para tentar em python, então vou colocar o que recebi:

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

Ele aceita entrada de stdin ou como argumento (-i) e, por padrão, grava uma linha por 1/10 de segundo, mas isso pode ser alterado com outro argumento (-d).


Obrigado. Eu estava começando a desenvolver algo semelhante a essa idéia em Python quando me deparei com este Q & Ad. Observo que o Python também suporta select docs.python.org/3/library/select.html de maneira semelhante ao Perl, conforme usado na resposta de F. Hauri.
ybull 28/01
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.