tail -f, вставить разрыв строки после того, как журнал простаивает в течение 3 секунд?

14

При выполнении tail -f error.log, как программно вставить разрыв строки после того, как ничего не было добавлено в файл в течение 3 секунд?

(очевидно, как только один разрыв строки был добавлен, никакой другой разрыв строки не должен быть добавлен, пока другие строки текста не будут добавлены в файл журнала)

Например, эти строки добавляются в error.log:

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

Это будет вывод в консоли:

foo
bar
boo

2far
2foo
2bar
2boo

2far
Седрик
источник
Вы могли бы, вероятно, адаптировать мою функцию в askubuntu.com/a/993821/158442 , или использовать, tsчтобы добавить временную метку к выходу и обработать временные метки
muru
1
Стоит отметить, что если вы делаете это в интерактивном режиме, вы можете просто нажать клавишу ввода несколько раз. :)
Подстановочный

Ответы:

12

Вы всегда можете реализовать tail -f(хорошо здесь, если вы не раскомментируете seek(), скорее tail -n +1 -fкак мы выкидываем весь файл) вручную, perlнапример:

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

Или позвольте tail -fсделать хвост и использовать perlдля вставки новых строк, если нет ввода в течение 3 секунд:

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

Они предполагают, что сам вывод не замедляется (например, когда вывод идет в канал, который активно не читается).

Стефан Шазелас
источник
Мне потребовалось много времени, чтобы понять, почему второй действительно работает :)
Хоббс
Я попробовал первый, и он напечатал ВСЕ файлы заранее, поэтому он не оптимален. Второй работает как шарм. Я добавил "tail -n 0 -f $ 1 |" опция (-n 0), чтобы избежать отображения старых строк файлов.
Седрик
Небольшой вопрос: как я могу изменить второе решение, чтобы отображать дополнительную строку тире (-------) через 10 секунд? (Я пробовал несколько способов, но ничего не могу сделать)
Седрик
1
@Cedric, смотрите правку для вашего первого пункта. Ваше второе требование будет проще с первым подходом.
Стефан Шазелас
8

bash+ dateрешение:

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
источник
В Bash вы можете использовать $SECONDSдля подсчета временных интервалов. Я думаю, это количество секунд с момента запуска оболочки, а не то, что это имеет значение, если брать разницу.
ilkkachu
@ilkkachu, или read -tили $TMOUT. $SECONDSсломан в bashа mksh. time bash -c 'while ((SECONDS < 3)); do :; done'будет длиться от 2 до 3 секунд. Лучше использовать вместо этого zsh или ksh93 здесь (с typeset -F SECONDS)
Стефан Шазелас
@ StéphaneChazelas, я не думаю, что это отличается от использования date +%s. Оба дают время в полных секундах, что приводит к тому, что интервал от, скажем, 1,9 до 4,0 выглядит как 3 полных секунды, хотя на самом деле он равен 2,1. Трудно обойти это, если все, что вы не можете получить доступ к доли секунды. Но да, они, вероятно, должны спать здесь вместо занятой, а затем read -tмогли бы также использоваться. Даже если вы спите вручную, все time bash -c 'while [[ $SECONDS -lt 3 ]]; do sleep 1; done'работает отлично.
ilkkachu
1
с ksh93 и zsh все в порядке (раньше zsh не делал). Даже с целым числом $ SECONDS, настройка SECONDS=0гарантирует, что $SECONDSбудет достигать 1 ровно за 1 секунду. Это не тот случай, bashкогда он используется time()для отслеживания $SECONDSвместо gettimeofday(). Некоторое время назад я сообщал об ошибках в mksh, zsh и bash, только zsh был исправлен. (Хороший вопрос о том, что проблема та же самая с date +%s). Обратите внимание, что это не занятый цикл, так как мы читаем с выхода по каналу tail -f.
Стефан Шазелас
+1 и Bash имеет «ярлык» , используя встроенный printfэмулировать dateбез внешних инструментов или подстановки команд: printf -v t '%(%s)T' -1.
Дэвид Фёрстер
6

Pythonрешение (с динамическим аргументом промежутка времени ):

tailing_by_time.py сценарий:

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

Использование:

tail -f error.log | python tailing_by_time.py 3
RomanPerekhrest
источник