tail -f, wstawić podziałkę, gdy log jest bezczynny przez 3 sekundy?


14

Kiedy robisz a tail -f error.log, jak wstawić programowo podział linii po tym, jak nic nie zostało dodane do pliku przez 3 sekundy?

(oczywiście po dodaniu jednego podziału wiersza nie należy dodawać żadnego innego podziału wiersza, dopóki inne wiersze tekstu nie zostaną dodane do pliku dziennika)

Na przykład te linie są dołączane do error.log:

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

To byłoby wyjście w konsoli:

foo
bar
boo

2far
2foo
2bar
2boo

2far

Prawdopodobnie możesz dostosować moją funkcję w askubuntu.com/a/993821/158442 lub użyć, tsaby dodać znacznik czasu do wyjścia i przetworzyć znaczniki czasu
muru

1
Warto wspomnieć, że jeśli robisz to interaktywnie, możesz po prostu nacisnąć klawisz Enter kilka razy. :)
Wildcard

Odpowiedzi:


12

Zawsze tail -fmożesz ręcznie zaimplementować (cóż tutaj, chyba że cofniesz komentarz seek(), bardziej jak tail -n +1 -fzrzucamy cały plik) ręcznie, perlna przykład:

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

Lub tail -fwykonaj ogonowanie i użyj, perlaby wstawić znaki nowej linii, jeśli nie ma danych wejściowych przez 3 sekundy:

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

Zakładają, że samo wyjście nie jest spowalniane (jak wtedy, gdy wyjście trafia do potoku, który nie jest aktywnie odczytywany).


Długo mi zajęło ustalenie, dlaczego drugi tak naprawdę działa :)
hobbs

Wypróbowałem pierwszy i wydrukowałem WSZYSTKIE pliki wcześniej, więc nie jest optymalny. Drugi działa jak urok. Dodałem „tail -n 0 -f $ 1 |” opcja (-n 0), aby uniknąć wyświetlania starych wierszy plików.
Cedric

Małe pytanie: Jak mogę zmienić drugie rozwiązanie, aby wyświetlać dodatkową linię kresek (-------) po 10 sekundach? (Próbowałem na wiele sposobów, ale nic nie mogę zrobić)
Cedric

1
@Cedric, zobacz edycję pierwszego punktu. Twoje drugie wymaganie byłoby łatwiejsze przy pierwszym podejściu.
Stéphane Chazelas

8

bash+ daterozwiązanie:

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)

W Bash możesz używać $SECONDSdo zliczania przedziałów czasowych. Myślę, że jest to liczba sekund od uruchomienia powłoki, a nie to, że ma to znaczenie przy przyjmowaniu różnicy.
ilkkachu

@ilkkachu, lub read -tlub $TMOUT. $SECONDSjest włamany bashi mksh. time bash -c 'while ((SECONDS < 3)); do :; done'potrwa od 2 do 3 sekund. Lepiej używać zsh lub ksh93 zamiast tutaj (z typeset -F SECONDS)
Stéphane Chazelas

@ StéphaneChazelas, nie sądzę, że jest inaczej niż za pomocą date +%s. Oba dają czas w pełnych sekundach, co powoduje, że przedział od, powiedzmy, 1,9 do 4,0 wygląda jak 3 pełne sekundy, mimo że tak naprawdę to 2,1. Trudno to obejść, jeśli nie masz dostępu do ułamków sekund. Ale tak, prawdopodobnie powinni spać tutaj zamiast busyloopowania, a następnie read -trównie dobrze mogliby zostać wykorzystani. Nawet jeśli śpisz ręcznie, time bash -c 'while [[ $SECONDS -lt 3 ]]; do sleep 1; done'działa dobrze.
ilkkachu

1
ksh93 i zsh są z tym OK (zsh nie było). Nawet z liczbą całkowitą $ SECONDS ustawienie SECONDS=0zapewnia $SECONDSosiągnięcie 1 w dokładnie 1 sekundę. Nie jest tak w przypadku, bashgdy używa time()do śledzenia $SECONDSzamiast gettimeofday(). Zgłaszałem błędy do mksh, zsh i bash jakiś czas temu, naprawiono tylko zsh. (dobra uwaga, że ​​problem jest taki sam date +%s). Zauważ, że to nie jest busyloop, ponieważ czytamy z wyjścia tail -fponad potokiem.
Stéphane Chazelas

+1 i Bash ma „skrót” za pomocą wbudowanego printfnaśladować datebez użycia narzędzi zewnętrznych lub podstawienia polecenia: printf -v t '%(%s)T' -1.
David Foerster

6

Pythonrozwiązanie (z argumentem dynamicznej przerwy czasowej ):

tailing_by_time.py scenariusz:

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

Stosowanie:

tail -f error.log | python tailing_by_time.py 3
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.