tail -f, inserire l'interruzione di riga dopo che il registro è inattivo per 3 secondi?


14

Quando si esegue un tail -f error.log, come inserire a livello di codice un'interruzione di riga dopo che non è stato aggiunto nulla al file per 3 secondi?

(ovviamente, una volta aggiunta un'interruzione di riga, non è necessario aggiungere altre interruzioni di riga fino a quando non vengono aggiunte altre righe di testo al file di registro)

Ad esempio, queste righe vengono aggiunte a error.log:

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

Questo sarebbe l'output nella console:

foo
bar
boo

2far
2foo
2bar
2boo

2far

Probabilmente potresti adattare la mia funzione in askubuntu.com/a/993821/158442 o utilizzare tsper aggiungere il timestamp all'output ed elaborare i timestamp
muru

1
Vale la pena ricordare che se lo stai facendo in modo interattivo, puoi semplicemente premere il tasto Invio un sacco di volte. :)
Wildcard il

Risposte:


12

Potresti sempre implementare il tail -f(bene qui, a meno che tu non abbia decommentato il seek(), più come tail -n +1 -fquando stiamo scaricando l'intero file) a mano con perlper esempio:

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

Oppure lascia tail -ffare la coda e usa perlper inserire le nuove righe se non c'è input per 3 secondi:

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

Si presume che l'uscita stessa non venga rallentata (come quando l'uscita va a una pipe che non viene letta attivamente).


Mi ci è voluto molto tempo per capire perché il secondo funziona davvero :)
hobbs il

Ho provato il primo e ho stampato TUTTI i file prima, quindi non è ottimale. Il secondo funziona come un incantesimo. Ho aggiunto "tail -n 0 -f $ 1 |" opzione (-n 0) per evitare di visualizzare le vecchie righe di file.
Cedric,

Piccola domanda: come posso modificare la seconda soluzione per visualizzare una linea aggiuntiva di trattini (-------) dopo 10 secondi? (Ho provato diversi modi, ma non riesco a far funzionare nulla)
Cedric,

1
@Cedric, vedi modifica per il tuo primo punto. Il tuo secondo requisito sarebbe più semplice con il primo approccio.
Stéphane Chazelas,

8

bash+ datesoluzione:

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)

In Bash, puoi usare $SECONDSper contare gli intervalli di tempo. Penso che sia il numero di secondi dall'avvio della shell, non che importa quando si fa la differenza.
ilkkachu,

@ilkkachu o read -toppure $TMOUT. $SECONDSè rotto bashe mksh. time bash -c 'while ((SECONDS < 3)); do :; done'durerà tra 2 e 3 secondi. Meglio usare zsh o ksh93 invece qui (con typeset -F SECONDS)
Stéphane Chazelas

@ StéphaneChazelas, non credo sia diverso dall'uso date +%s. Entrambi danno il tempo in secondi interi, il che ha l'effetto che l'intervallo, per esempio, da 1,9 a 4,0 assomigli a 3 secondi interi, anche se in realtà è 2.1. È difficile aggirare il problema se tutto ciò non è possibile accedere ai secondi frazionari. Ma sì, probabilmente dovrebbero dormire qui invece di occuparsi, e quindi read -tpotrebbero anche essere usati. Anche se dormi manualmente, time bash -c 'while [[ $SECONDS -lt 3 ]]; do sleep 1; done'funziona bene.
ilkkachu,

1
ksh93 e zsh sono d'accordo con ciò (zsh non lo faceva). Anche con numeri interi $ SECONDI, l'impostazione SECONDS=0garantisce che $SECONDSraggiungerà 1 in esattamente 1 secondo. Questo non è il caso di bashcome usa time()per tracciare $SECONDSinvece di gettimeofday(). Ho segnalato bug a mksh, zsh e bash qualche tempo fa, solo zsh è stato corretto. (buon punto sul fatto che il problema è lo stesso con date +%s). Nota che qui non è occupato, visto che stiamo leggendo dall'output di tail -fover a pipe.
Stéphane Chazelas,

+1 e Bash ha una "scorciatoia" utilizzando il built-in printfper emulare datesenza attrezzi esterni o sostituzione di comando: printf -v t '%(%s)T' -1.
David Foerster,

6

Pythonsoluzione (con argomento intervallo di tempo dinamico ):

tailing_by_time.py script:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.