tail -f, insira quebra de linha após o log ficar inativo por 3 segundos?

14

Ao fazer um tail -f error.log, como inserir programaticamente uma quebra de linha depois que nada foi anexado ao arquivo por 3 segundos?

(obviamente, depois que uma quebra de linha foi adicionada, nenhuma outra quebra de linha deve ser adicionada até que outras linhas de texto sejam adicionadas ao arquivo de log)

Por exemplo, essas linhas são associadas ao error.log:

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

Essa seria a saída no console:

foo
bar
boo

2far
2foo
2bar
2boo

2far
Cedric
fonte
Você provavelmente poderia se adaptar a minha função em askubuntu.com/a/993821/158442 ou uso tspara adicionar timestamping para a saída e processar os timestamps
Muru
1
Vale ressaltar que, se você estiver fazendo isso de maneira interativa, basta pressionar a tecla Enter várias vezes. :)
Curinga

Respostas:

12

Você sempre pode implementar o tail -f(bem aqui, a menos que descomente o seek(), mais como tail -n +1 -festamos lançando o arquivo inteiro) manualmente, perlpor exemplo:

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

Ou deixe tail -fo tailing e use perlpara inserir as novas linhas se não houver entrada por 3 segundos:

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

Eles assumem que a saída em si não é mais lenta (como quando a saída vai para um canal que não é lido ativamente).

Stéphane Chazelas
fonte
Levei muito tempo para descobrir por que o segundo realmente funciona :)
hobbs
Eu tentei o primeiro, e ele imprimiu TODOS os arquivos antes, então não é o ideal. O segundo funciona como um encanto. Eu adicionei o "tail -n 0 -f $ 1 |" opção (-n 0) para evitar a exibição das linhas antigas de arquivos.
Cedric
Pequena pergunta: como alterar a segunda solução para exibir uma linha adicional de hífens (-------) após 10 segundos? (Eu tentei várias maneiras, mas não pode fazer o trabalho de qualquer coisa)
Cedric
1
@ Cedric, veja editar para o seu primeiro ponto. Seu segundo requisito seria mais fácil com a primeira abordagem.
Stéphane Chazelas
8

bash+ datesolução:

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
fonte
No Bash, você pode usar $SECONDSpara contar intervalos de tempo. Eu acho que é o número de segundos desde que o shell foi iniciado, não que isso importe ao fazer a diferença.
22418 ilkkachu
@ilkkachu, ou read -tou $TMOUT. $SECONDSestá quebrado bashe mksh. time bash -c 'while ((SECONDS < 3)); do :; done'durará entre 2 e 3 segundos. Melhor usar zsh ou ksh93 vez aqui (com typeset -F SECONDS)
Stéphane Chazelas
@ StéphaneChazelas, acho que não é diferente de usar date +%s. Ambos fornecem o tempo em segundos completos, o que faz com que o intervalo de, digamos, 1,9 a 4,0 pareça 3 segundos completos, mesmo que seja realmente 2,1. É difícil contornar isso, se tudo o que você não consegue acessar são os segundos fracionários. Mas sim, eles provavelmente deveriam dormir aqui em vez de busylooping, e então read -tpoderiam muito bem ser usados. Mesmo se você dorme manualmente, time bash -c 'while [[ $SECONDS -lt 3 ]]; do sleep 1; done'funciona muito bem.
22618 ilkkachu
1
ksh93 e zsh estão bem com isso (o zsh não costumava fazer isso). Mesmo com o número inteiro $ SECONDS, a configuração SECONDS=0garante que $SECONDSatingirá 1 em exatamente 1 segundo. Esse não é o caso, bashpois ele usa time()para rastrear em $SECONDSvez de gettimeofday(). Relatei bugs para mksh, zsh e bash há algum tempo, apenas o zsh foi corrigido. (ponto positivo sobre o problema ser o mesmo date +%s). Observe que não é um busyloop aqui, como estamos lendo a partir da saída de tail -fmais de um tubo.
Stéphane Chazelas 22/02
+1 e Bash tem um "atalho" usando o built-in printfpara emular datesem ferramentas externas ou substituição de comando: printf -v t '%(%s)T' -1.
David Foerster
6

Pythonsolução (com argumento de intervalo de tempo dinâmico ):

tailing_by_time.py roteiro:

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
fonte