tail -f, inserte el salto de línea después de que el registro esté inactivo durante 3 segundos?

14

Al hacer una tail -f error.log, ¿cómo insertar programáticamente un salto de línea después de que no se haya agregado nada al archivo durante 3 segundos?

(obviamente, una vez que se ha agregado un salto de línea, no se debe agregar ningún otro salto de línea hasta que se agreguen otras líneas de texto al archivo de registro)

Por ejemplo, estas líneas se agregan a error.log:

foo
bar
boo [[wait 4 seconds]]
2far
2foo
2bar
2boo [[wait 40 seconds]]
2far

Este sería el resultado en la consola:

foo
bar
boo

2far
2foo
2bar
2boo

2far
Cedric
fuente
Probablemente podría adaptar mi función en askubuntu.com/a/993821/158442 , o usarla tspara agregar marcas de tiempo a la salida y procesar las marcas de tiempo
muru
1
Vale la pena mencionar que si lo está haciendo de manera interactiva, puede presionar la tecla Intro varias veces. :)
Comodín

Respuestas:

12

Siempre puede implementar el tail -f(bueno aquí, a menos que descomente el seek(), más como tail -n +1 -fcuando estamos volcando todo el archivo) a mano con, perlpor ejemplo:

perl -e '
  $| = 1;
  # seek STDIN, 0, 2; # uncomment if you want to skip the text that is
                      # already there. Or if using the ksh93 shell, add
                      # a <((EOF)) after < your-file
  while (1) {
    if ($_ = <STDIN>) {
      print; $t = 0
    } else {
      print "\n"            if $t == 3;
      # and a line of "-"s after 10 seconds:
      print "-" x 72 . "\n" if $t == 10;
      sleep 1;
      $t++;
    }
  }' < your-file

O deje tail -fque se sigan y utilice perlpara insertar las nuevas líneas si no hay entrada durante 3 segundos:

tail -f file | perl -pe 'BEGIN{$SIG{ALRM} = sub {print "\n"}} alarm 3'

Aquellos suponen que la salida en sí no se ralentiza (como cuando la salida va a una tubería que no se lee activamente).

Stéphane Chazelas
fuente
Me tomó mucho tiempo descubrir por qué el segundo realmente funciona :)
hobbs
He probado el primero, e imprimió TODOS los archivos de antemano, por lo que no es óptimo. El segundo funciona a las mil maravillas. He agregado el "tail -n 0 -f $ 1 |" opción (-n 0) para evitar mostrar las viejas líneas de archivos.
Cedric
Pequeña pregunta: ¿cómo podría modificar la segunda solución para mostrar una línea adicional de guiones (-------) después de 10 segundos? (He intentado varias formas, pero no puedo hacer que nada funcione)
Cedric
1
@Cedric, vea editar para su primer punto. Su segundo requisito sería más fácil con el primer enfoque.
Stéphane Chazelas
8

bash+ datesolución:

while IFS= read -r line; do        
    prev=$t         # get previous timestamp value
    t=$(date +%s)   # get current timestamp value
    [[ ! -z "$prev" ]] && [[ "$((t-prev))" -ge 3 ]] && echo ""
    echo "$line"    # print current line
done < <(tail -f error.log)
RomanPerekhrest
fuente
En Bash, puede usar $SECONDSpara contar intervalos de tiempo. Creo que es la cantidad de segundos desde que se inició el shell, no es importante cuando se toma la diferencia.
ilkkachu
@ilkkachu, o read -to $TMOUT. $SECONDSestá roto bashy mksh. time bash -c 'while ((SECONDS < 3)); do :; done'durará entre 2 y 3 segundos. Mejor usar zsh o ksh93 en su lugar aquí (con typeset -F SECONDS)
Stéphane Chazelas
@ StéphaneChazelas, no creo que sea diferente de usar date +%s. Ambos dan el tiempo en segundos completos, lo que tiene el efecto de que el intervalo de, por ejemplo, 1.9 a 4.0 parece 3 segundos completos, aunque en realidad es 2.1. Es difícil evitar eso si no puedes acceder a los segundos fraccionarios. Pero sí, probablemente deberían dormir aquí en lugar de estar ocupados, y luego read -tpodrían ser utilizados. Incluso si duermes manualmente, time bash -c 'while [[ $SECONDS -lt 3 ]]; do sleep 1; done'funciona bien.
ilkkachu
1
ksh93 y zsh están bien con eso (zsh no solía hacerlo). Incluso con el entero $ SECONDS, la configuración SECONDS=0asegura que $SECONDSalcanzará 1 en exactamente 1 segundo. Ese no es el caso, bashya que utiliza time()para rastrear en $SECONDSlugar de gettimeofday(). Informé de errores a mksh, zsh y bash hace algún tiempo, solo se solucionó zsh. (Buen punto sobre que el problema es el mismo con date +%s). Tenga en cuenta que no es un loop ocupado aquí, ya que estamos leyendo de la salida de tail -fmás de una tubería.
Stéphane Chazelas
1 y Bash tiene un "atajo" utilizando el incorporado en printfemular datesin necesidad de herramientas externas o sustitución de comandos: printf -v t '%(%s)T' -1.
David Foerster
6

Pythonsolución (con argumento dinámico de intervalo de tiempo ):

tailing_by_time.py guión:

import time, sys

t_gap = int(sys.argv[1])    # time gap argument
ts = 0
while True:
    line = sys.stdin.readline().strip()    # get/read current line from stdin
    curr_ts = time.time()                  # get current timestamp
    if ts and curr_ts - ts >= t_gap:
        print("")                          # print empty line/newline
    ts = curr_ts
    if line:
        print(line)                        # print current line if it's not empty

Uso:

tail -f error.log | python tailing_by_time.py 3
RomanPerekhrest
fuente