извлечение последних 10 минут из файла журнала [дубликат]

этот вопрос уже есть ответ здесь:

пытаясь найти простой способ просмотра последних событий (менее 10 минут), я пробовал это:

awk "/^$(date --date="-10 min" "+%b %_d %H:%M")/{p++} p" /root/test.txt

но это работает не так, как ожидалось...

файлы журнала в форме :

Dec 18 09:48:54 Blah
Dec 18 09:54:47 blah bla
Dec 18 09:55:33 sds
Dec 18 09:55:38 sds
Dec 18 09:57:58 sa
Dec 18 09:58:10 And so on...

6 ответов


вы можете сопоставить диапазон дат с помощью простого сравнения строк, например:

d1=$(date --date="-10 min" "+%b %_d %H:%M")
d2=$(date "+%b %_d %H:%M")
while read line; do
    [[ $line > $d1 && $line < $d2 || $line =~ $d2 ]] && echo $line
done

например, если d1='Dec 18 10:19' и d2='Dec 18 10:27' тогда выход будет:

Dec 18 10:19:16
Dec 18 10:19:23
Dec 18 10:21:03
Dec 18 10:22:54
Dec 18 10:27:32

или через awk если вы хотите:

awk -v d1="$d1" -v d2="$d2" ' > d1 &&  < d2 ||  ~ d2'

вот хороший инструмент диапазон любой Вы хотите от -10 до сих пор

sed -n "/^$(date --date='10 minutes ago' '+%b %_d %H:%M')/,$p" /var/log/blaaaa

это (обычная) работа для perl!:

простой и эффективный:

perl -MDate::Parse -ne 'print if/^(.{15})\s/&&str2time()>time-600' /path/log

эта версия печатает последние 10 минут события, до теперь, С помощью


на Баш можно использовать date команда для анализа временных меток. The спецификатор формата"%s " преобразует заданную дату в количество секунд с 1970-01-01 00:00:00 UTC. Это простое целое число легко и точно выполнять основную арифметику.

если вы хотите сообщения журнала от последних 10 минут фактического времени:

now10=$(($(date +%s) - (10 * 60)))

while read line; do
    [ $(date -d "${line:0:15}" +%s) -gt $now10 ] && printf "$line\n"
done < logfile

Примечание ${line:0:15} выражение расширение параметра bash что дает первый 15 символов строки, т. е. сама метка времени.

если вы хотите, чтобы сообщения журнала За последние 10 минут относительно конца журнала:

$ lastline=$(tail -n1 logfile)
$ last10=$(($(date -d "$lastline" +%s) - (10 * 60)))
$ while read line; do
> [ $(date -d "${line:0:15}" +%s) -gt $last10 ] && printf "$line\n"
> done < logfile
Dec 18 10:19:16
Dec 18 10:19:23
Dec 18 10:21:03
Dec 18 10:22:54
Dec 18 10:27:32
$ 

вот умеренное повышение производительности на:

$ { while read line; do
> [ $(date -d "${line:0:15}" +%s) -gt $last10 ] && printf "$line\n" && break
> done ; cat ; }  < logfile
Dec 18 10:19:16
Dec 18 10:19:23
Dec 18 10:21:03
Dec 18 10:22:54
Dec 18 10:27:32
$ 

это предполагает, что записи журнала находятся в строгом хронологическом порядке. Как только мы сопоставим метку времени в вопросе, мы выходим из цикла for, а затем просто используем cat сбросить оставшиеся записи.


в python вы можете сделать следующее:

from datetime import datetime

astack=[]
with open("x.txt") as f:
    for aline in f:
        astack.append(aline.strip())
lasttime=datetime.strptime(astack[-1], '%b %d %I:%M:%S')
for i in astack:
    if (lasttime - datetime.strptime(i, '%b %d %I:%M:%S')).seconds <= 600:
        print i

поместите строки из файла в стек (список python). поп последний элемент и получить разницу между последовательными элементами даты, пока вы не получите разницу менее 600 секунд.

запуск на Вашем входе, я получаю следующее:

Dec 18 10:19:16
Dec 18 10:19:23
Dec 18 10:21:03
Dec 18 10:22:54
Dec 18 10:27:32

решение Ruby (протестировано на ruby 1.9.3)

вы можете передать дни, часы, минуты или секунды в качестве параметра, и он будет искать выражение и на указанный файл (или каталог, в этом случае он будет добавлять '/ * ' к имени):

в вашем случае просто вызовите скрипт следующим образом: $0-m 10 "expression" log_file

Примечание: также, если вы знаете местоположение "ruby", измените shebang (первая строка скрипта), для безопасности причины.

#! /usr/bin/env ruby

require 'date'
require 'pathname'

if ARGV.length != 4
        $stderr.print "usage: #{} -d|-h|-m|-s time expression log_file\n"
        exit 1
end
begin
        total_amount = Integer ARGV[1]
rescue ArgumentError
        $stderr.print "error: parameter 'time' must be an Integer\n"
        $stderr.print "usage: #{} -d|-h|-m|-s time expression log_file\n"
end

if ARGV[0] == "-m"
        gap = Rational(60, 86400)
        time_str = "%b %d %H:%M"
elsif ARGV[0] == "-s"
        gap = Rational(1, 86400)
        time_str = "%b %d %H:%M:%S"
elsif ARGV[0] == "-h"
        gap = Rational(3600, 86400)
        time_str = "%b %d %H"
elsif ARGV[0] == "-d"
        time_str = "%b %d"
        gap = 1
else
        $stderr.print "usage: #{} -d|-h|-m|-s time expression log_file\n"
        exit 1
end

pn = Pathname.new(ARGV[3])
if pn.exist?
        log = (pn.directory?) ? ARGV[3] + "/*" : ARGV[3]
else
        $stderr.print "error: file '" << ARGV[3] << "' does not exist\n"
        $stderr.print "usage: #{} -d|-h|-m|-s time expression log_file\n"
end

search_str = ARGV[2]
now = DateTime.now

total_amount.times do
        now -= gap
        system "cat " << log << " | grep '" << now.strftime(time_str) << ".*" << search_str << "'"
end