tail -f, insérer un saut de ligne après que le journal est inactif pendant 3 secondes?


14

Lorsque vous faites un tail -f error.log, comment insérer par programmation un saut de ligne après que rien n'a été ajouté au fichier pendant 3 secondes?

(évidemment, une fois qu'un saut de ligne a été ajouté, aucun autre saut de ligne ne doit être ajouté jusqu'à ce que d'autres lignes de texte soient ajoutées au fichier journal)

Par exemple, ces lignes sont ajoutées à error.log:

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

Ce serait la sortie dans la console:

foo
bar
boo

2far
2foo
2bar
2boo

2far

Vous pourriez probablement adapter ma fonction dans askubuntu.com/a/993821/158442 , ou utiliser tspour ajouter un horodatage à la sortie et traiter les horodatages
— muru

1
Il convient de mentionner que si vous le faites de manière interactive, vous pouvez simplement appuyer sur la touche Entrée plusieurs fois. :)
— Wildcard

Réponses:


12

Vous pouvez toujours implémenter le tail -f(enfin ici, à moins que vous ne décommentiez le seek(), plus comme tail -n +1 -fnous vidons tout le fichier) à la main avec perlpar exemple:

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 laissez tail -ffaire la queue et utilisez perlpour insérer les sauts de ligne s'il n'y a pas d'entrée pendant 3 secondes:

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

Ceux-ci supposent que la sortie elle-même n'est pas ralentie (comme lorsque la sortie va vers un tube qui n'est pas activement lu).


Il m'a fallu beaucoup de temps pour comprendre pourquoi le second fonctionne réellement :)
— hobbs

J'ai essayé le premier, et il a imprimé TOUS les fichiers avant, donc ce n'est pas optimal. Le second fonctionne comme un charme. J'ai ajouté le "tail -n 0 -f $ 1 |" option (-n 0) pour éviter d'afficher les anciennes lignes de fichiers.
— Cedric

Petite question: comment modifier la deuxième solution pour afficher une ligne supplémentaire de tirets (-------) après 10 secondes? (J'ai essayé plusieurs façons, mais je ne peux rien faire fonctionner)
— Cedric

1
@Cedric, voir modifier pour votre premier point. Votre deuxième exigence serait plus facile avec la première approche.
— Stéphane Chazelas

8

bash+ datesolution:

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)

Dans Bash, vous pouvez utiliser $SECONDSpour compter les intervalles de temps. Je pense que c'est le nombre de secondes écoulées depuis le démarrage de la coque, pas que cela soit important pour prendre une différence.
— ilkkachu

@ilkkachu, ou read -tou $TMOUT. $SECONDSest cassé bashet mksh. time bash -c 'while ((SECONDS < 3)); do :; done'durera entre 2 et 3 secondes. Mieux vaut utiliser zsh ou ksh93 à la place ici (avec typeset -F SECONDS)
— Stéphane Chazelas

@ StéphaneChazelas, je ne pense pas que ce soit différent de l'utilisation date +%s. Les deux donnent le temps en secondes complètes, ce qui a pour effet que l'intervalle de, disons, 1,9 à 4,0 ressemble à 3 secondes complètes, même si c'est vraiment 2,1. Il est difficile de contourner cela si vous ne pouvez pas accéder à la fraction de seconde. Mais oui, ils devraient probablement dormir ici au lieu de se déplacer, et read -tpourraient alors tout aussi bien être utilisés. Même si vous dormez manuellement, cela time bash -c 'while [[ $SECONDS -lt 3 ]]; do sleep 1; done'fonctionne très bien.
— ilkkachu

1
ksh93 et ​​zsh sont OK avec ça (zsh ne le faisait pas). Même avec un entier $ SECONDS, le réglage SECONDS=0garantit qu'il $SECONDSatteindra 1 en 1 seconde exactement. Ce n'est pas le cas bashcar il utilise time()pour suivre $SECONDSau lieu de gettimeofday(). J'ai signalé des bogues à mksh, zsh et bash il y a quelque temps, seul zsh a été corrigé. (bon point sur le problème étant le même avec date +%s). Notez que ce n'est pas un busyloop ici, comme nous le lisons à partir de la sortie d' tail -fun tube.
— Stéphane Chazelas

+1 et Bash a un « raccourci » en utilisant le haut- printfÉmuler datesans outils externes ou substitution de commande: printf -v t '%(%s)T' -1.
— David Foerster

6

Pythonsolution (avec argument d' écart de temps dynamique ):

tailing_by_time.py scénario:

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

Usage:

tail -f error.log | python tailing_by_time.py 3
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.