Archivo Cat al terminal a una velocidad particular de líneas por segundo

15

Soy flojo y podría escribir un guión para hacer esto, pero incluso soy demasiado flojo para pensar cómo hacerlo.

A menudo hago cosas como:

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

A veces, cuando veo el resultado largo de un experimento, me gusta dejar que la página se desplace y vea cómo se forman y se dispersan los patrones sucesivos. Pero usar cat en un archivo con 1 millón de líneas termina en quizás 5 segundos. Esto es demasiado rápido incluso para mí.

¿Hay alguna manera de reducir la velocidad de visualización del archivo, algo así como una 'utilidad de desplazamiento'? Quiero rápido, pero no 200 mil líneas por segundo (todo lo cual presumiblemente la pantalla nunca se registraría de todos modos).

Algo como

cris$ scroll -lps=300 output.txt

Y luego, sentarme y mirar pasar 300 líneas por segundo sería ideal, me imagino.

Cris Stringfellow
fuente
77
Intenta algo como cat FILENAME | pv -l -L 900 -q. El límite está en bytes por segundo, no en líneas por segundo, así que estoy haciendo de este un comentario, no una respuesta.
David Schwartz
Ok, bueno, esa es una utilidad genial, y eso funciona en parte. Pero sí, es un poco entrecortado ya que va detrás de bps, no lps.
Cris Stringfellow

Respuestas:

17

Corto y legible :

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

Publico estas soluciones porque son pequeñas y legibles, ya que los comentarios de la respuesta de DMas parecen promover este tipo de solución.

Pero odio esto porque: para esta carrera, ¡Perl se bifurcará a /bin/sleep300x / segundos!

¡Este es un gran consumidor de recursos! También un mal buenas soluciones !

Usando sueño incorporado en

Desafortunadamente, la construcción sleepse limita a los enteros. Entonces tenemos que usar selecten su lugar:

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

Bajo perl, print while <>podría ser reemplazado por el -pinterruptor:

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

Intentemos:

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

Explicación:

  • 300 líneas / seg significa 1 línea por 0.0033333333 segundos.

  • printsin argumento imprime, $_que es el espacio de entrada predeterminado .

  • llamado como ... | perl -e, ... | perl -neo ... | perl -pe, la entrada estándar se asignaría automáticamente a *STDINcuál es el descriptor de archivo predeterminado , por <>lo que haría lo mismo <STDIN>que se leerá desde la entrada estándar hasta que se llegue al $/( separador de registro de entrada que por defecto es una nueva línea ). En inglés, por defecto <>leerá una línea de la entrada estándar y asignará contenido a la $_variable.

  • &&es una condición y , pero se usa allí como un separador de comandos de cadena, por lo que después (con éxito) imprime una línea, haciendo el siguiente comando.

  • selectes un truco de programador para no usarsleep . Este comando está diseñado para atrapar eventos en descriptores de archivos (entradas y / o salidas, archivos, zócalos y / o zócalos de red). Con este comando, un programa podría esperar 3 tipos de eventos, alimentación lista para leer , alimentación lista para escribir y algún evento sucedió en la alimentación . El cuarto argumento es un tiempo de espera en segundos, por lo que la sintaxis es select <feeds where wait for input>, <feeds where having to write>, <feed where something could happen>, <timeout>.

Para mayor precisión, puede usar el 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: $.es el número de línea de entrada actual .

Mejor 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]...

El primer argumento lpses un argumento numérico opcional de línea por segundo (predeterminado: 300)

Nota: si el nombre de archivo sólo es numérico, puede que tenga que specifiy con ruta: ./3.

De catesta manera, podría pasar archivos dados como argumento o entrada estándar

Entonces podríamos:

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

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

Por diversión:

export TIMEFORMAT='%R' ;clear ;time seq 1 $((LINES-2)) | ./catLps.pl $((LINES-2))
F. Hauri
fuente
2
eso parece un vudú serio que estás haciendo allí. eso es genial, lo probé y funciona. Sin embargo, no tengo idea de cómo lo hiciste. ¿Qué demonios es Perl Select? undef? Puedo buscarlo. increíble.
Cris Stringfellow
2
@CrisStringfellow Ok, agregué algunas explicaciones y un script completo usando el Time::HiResmódulo perl para mayor precisión
F. Hauri
Dios mío. Esa es una respuesta asombrosa. Gracias. Traté de votarlo por segunda vez. Estoy aprendiendo algo leyendo tu maravillosa explicación.
Cris Stringfellow
2
También podría votar mis comentarios ;-)
F. Hauri
@CrisStringfellow Respuesta editada: mediante el uso de -pcambiar al comando perl, ¡el script se aligeró!
F. Hauri
11

solo usa awk con el sueño:

awk '{print $0; system("sleep .1");}' log.txt
DMas
fuente
Esto funcionó para mí y para mi situación fue la mejor opción en lugar de las opciones de script anteriores. No estoy seguro de por qué esta respuesta es rechazada.
Ciudadano Kepler el
2
A diferencia de la solución perl, es bastante legible.
Gunslinger
1
@Gunslinger: ¡La sintaxis system(*sleep .1")generará 10 bifurcaciones / segundos! Esto podría escribirse perl -pe 'system "sleep .1"' log.txt: Legible también, pero muy costoso (¡no
compatible con el
Yo también prefiero esta respuesta legible. Lo único es que activará el comando de suspensión de shell para cada línea que salga. Pero al ser un trazador de líneas legible perfecto, no me importa.
itsafire
0

Llego tarde a la fiesta, pero descubrí que este sería un ejercicio de aprendizaje útil para probar en Python, así que pondré lo que obtuve:

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

Acepta la entrada de stdin o como un argumento (-i) y por defecto escribe una línea por 1/10 de segundo, pero eso se puede cambiar con otro argumento (-d).

Grezzo
fuente
Gracias. Estaba empezando a desarrollar algo similar a esta idea en Python cuando me topé con este Q & Ad. Observo que Python también es compatible con select docs.python.org/3/library/select.html de manera similar a Perl como se usa en la respuesta de F. Hauri.
ybull