tail -f, masukkan line break setelah log kosong selama 3 detik?

14

Ketika melakukan a tail -f error.log, bagaimana cara memasukkan terputus secara terprogram setelah tidak ada yang ditambahkan ke file selama 3 detik?

(tentu saja, setelah satu jeda baris ditambahkan, tidak ada jeda baris lain yang harus ditambahkan sampai baris teks ditambahkan ke file log)

Misalnya, baris-baris ini ditambahkan ke error.log:

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

Ini akan menjadi output di konsol:

foo
bar
boo

2far
2foo
2bar
2boo

2far
Cedric
sumber
Anda mungkin dapat menyesuaikan fungsi saya di askubuntu.com/a/993821/158442 , atau gunakan tsuntuk menambahkan timestamping ke output dan memproses cap waktu
muru
1
Layak disebutkan bahwa jika Anda melakukannya secara interaktif, Anda bisa menekan tombol enter beberapa kali. :)
Wildcard

Jawaban:

12

Anda selalu dapat mengimplementasikan tail -f(yah di sini, kecuali Anda menghapus tanda komentar seek(), lebih seperti tail -n +1 -fsaat kita membuang seluruh file) dengan tangan perlmisalnya:

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

Atau biarkan tail -ftailing dan gunakan perluntuk memasukkan baris baru jika tidak ada input selama 3 detik:

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

Mereka menganggap bahwa output itu sendiri tidak melambat (seperti ketika output pergi ke pipa yang tidak aktif dibaca).

Stéphane Chazelas
sumber
Butuh waktu lama untuk mencari tahu mengapa yang kedua benar-benar bekerja :)
hobbs
Saya sudah mencoba yang pertama, dan itu mencetak SEMUA file sebelumnya, sehingga tidak optimal. Yang kedua bekerja seperti pesona. Saya telah menambahkan "tail -n 0 -f $ 1 |" opsi (-n 0) untuk menghindari menampilkan baris file lama.
Cedric
Pertanyaan kecil: Bagaimana saya bisa mengubah solusi kedua untuk menampilkan garis tanda hubung tambahan (-------) setelah 10 detik? (Saya telah mencoba berbagai cara, tetapi tidak dapat membuat sesuatu berhasil)
Cedric
1
@Cedric, lihat edit untuk poin pertama Anda. Persyaratan kedua Anda akan lebih mudah dengan pendekatan pertama.
Stéphane Chazelas
8

bash+ datesolusi:

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
sumber
Di Bash, Anda dapat menggunakan $SECONDSuntuk menghitung interval waktu. Saya pikir ini adalah jumlah detik sejak shell dimulai, bukan itu penting ketika mengambil perbedaan.
ilkkachu
@ilkkachu, atau read -tatau $TMOUT. $SECONDSrusak bashdan mksh. time bash -c 'while ((SECONDS < 3)); do :; done'akan bertahan antara 2 dan 3 detik. Lebih baik menggunakan zsh atau ksh93 sebagai gantinya di sini (dengan typeset -F SECONDS)
Stéphane Chazelas
@ StéphaneChazelas, saya tidak berpikir itu berbeda dari menggunakan date +%s. Keduanya memberikan waktu dalam detik penuh, yang memang memiliki efek bahwa interval dari, katakanlah, 1.9 hingga 4.0 terlihat seperti 3 detik penuh, meskipun itu benar-benar 2.1. Sulit untuk menyelesaikannya jika Anda tidak dapat mengakses detik pecahan. Tapi ya, mereka mungkin sebaiknya tidur di sini alih-alih sibuk, dan kemudian read -tbisa digunakan. Bahkan jika Anda tidur secara manual, tetap time bash -c 'while [[ $SECONDS -lt 3 ]]; do sleep 1; done'bekerja dengan baik.
ilkkachu
1
ksh93 dan zsh tidak masalah dengan itu (zsh digunakan untuk tidak). Bahkan dengan integer $ DETIK, pengaturan SECONDS=0memastikan bahwa $SECONDSakan mencapai 1 tepat 1 detik. Itu tidak terjadi dengan bashseperti yang digunakan time()untuk melacak, $SECONDSbukan gettimeofday(). Saya melaporkan bug ke mksh, zsh dan bash beberapa waktu lalu, hanya zsh yang diperbaiki. (Poin bagus tentang masalah ini sama dengan date +%s). Perhatikan bahwa ini bukan kesibukan di sini, karena kita membaca dari hasil tail -flebih dari satu pipa.
Stéphane Chazelas
1 dan Bash memiliki "jalan pintas" menggunakan built-in printfuntuk meniru datetanpa alat eksternal atau substitusi perintah: printf -v t '%(%s)T' -1.
David Foerster
6

Pythonsolusi (dengan argumen kesenjangan waktu dinamis ):

tailing_by_time.py naskah:

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

Pemakaian:

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