Bash 从日志文件中提取最后10分钟
为了找到一种观看最近事件的简单方法(不到10分钟),我尝试了以下方法:Bash 从日志文件中提取最后10分钟,bash,date,datetime,logfiles,perl,Bash,Date,Datetime,Logfiles,Perl,为了找到一种观看最近事件的简单方法(不到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
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...
在中,可以使用date
命令解析时间戳。这个这个简单的整数很容易就能精确地完成基本的算术运算
如果需要实际时间最后10分钟的日志消息:
now10=$(($(date +%s) - (10 * 60)))
while read line; do
[ $(date -d "${line:0:15}" +%s) -gt $now10 ] && printf "$line\n"
done < logfile
以下是对上述性能的轻微增强:
$ { 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
$
${读取行时;执行
>[$(日期-d“${line:0:15}”+%s)-gt$last10]&&printf“$line\n”&&break
>完成;cat;}<日志文件
12月18日10:19:16
12月18日10:19:23
12月18日10:21:03
12月18日10:22:54
12月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
您可以使用简单的字符串比较来匹配日期范围,例如:
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
或使用awk
,如果您愿意:
awk -v d1="$d1" -v d2="$d2" '$0 > d1 && $0 < d2 || $0 ~ d2'
awk-vd1=“$d1”-vd2=“$d2””$0>d1&&0
简介
这个答案很长,因为有三种不同的思考方式:1)快速或准确,2)纯和3)函数脚本
这是一个(普通的)工作!:
简单高效:
perl -MDate::Parse -ne 'print if/^(.{15})\s/&&str2time($1)>time-600' /path/log
此版本使用时间
功能打印最后10分钟事件,直到现在
您可以使用以下方法对此进行测试:
sudo cat /var/log/syslog |
perl -MDate::Parse -ne '
print if /^(\S+\s+\d+\s+\d+:\d+:\d+)\s/ && str2time($1) > time-600'
请注意,第一个表示只使用每行的前15个字符,而第二个构造使用更详细的regexp
作为perl脚本:last10m.pl
#!/usr/bin/perl -wn
use strict;
use Date::Parse;
print if /^(\S+\s+\d+\s+\d+:\d+:\d+)\s/ && str2time($1) > time-600
严格地说:从日志文件中提取最后10分钟
这意味着不是相对于当前时间,而是相对于日志文件中的最后一个条目:
检索期末有两种方法:
其中,逻辑上,日志文件的最后修改时间必须是最后一个条目的时间
因此,该命令可以变成:
perl -MDate::Parse -ne 'print if/^(.{15})\s/&&str2time($1)>'$(
date -r logfile +%s)
或者,您可以将最后一个条目作为参考:
perl -MDate::Parse -E 'open IN,"<".$ARGV[0];seek IN,-200,2;while (<IN>) {
$ref=str2time($1) if /^(\S+\s+\d+\s+\d+:\d+:\d+)/;};seek IN,0,0;
while (<IN>) {print if /^(.{15})\s/&&str2time($1)>$ref-600}' logfile
存储此脚本并运行:
cat >last10min.sh
chmod +x last10min.sh
sudo cat /var/log/syslog | ./last10min.sh
严格地说:从日志文件中提取最后10分钟
只需替换第10行,但必须将文件名放在脚本中,而不要将其用作筛选器:
#!/bin/bash
declare -A month
for i in {1..12};do
LANG=C printf -v var "%(%b)T" $(((i-1)*31*86400))
month[$var]=$i
done
read now < <(date -d "$(tail -n1 $1|head -c 15)" +%s)
printf -v ref "%(%m%d%H%M%S)T" $((now-600))
export -A month
{
while read line;do
printf -v crt "%02d%02d%02d%02d%02d" ${month[${line:0:3}]} \
$((10#${line:4:2})) $((10#${line:7:2})) $((10#${line:10:2})) \
$((10#${line:13:2}))
[ $crt -gt $ref ] && break
done
cat
} <$1
用法:
recentLog[文件名][分钟][时间长度]
- 日志文件的文件名
max before now要显示的行数minutes
(默认值从行开始的时间长度
)15
- Ruby解决方案(在Ruby 1.9.3上测试)
您可以将天、小时、分钟或秒作为参数传递,它将在指定的文件(或目录,在这种情况下,它将在名称后面附加“/*”)上搜索表达式和:
在您的情况下,只需像这样调用脚本:$0-m10“expression”log\u文件
注意:如果您知道“ruby”的位置,请更改shebang(脚本的第一行),
出于安全原因
#! /usr/bin/env ruby
require 'date'
require 'pathname'
if ARGV.length != 4
$stderr.print "usage: #{$0} -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: #{$0} -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: #{$0} -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: #{$0} -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
#/usr/bin/env ruby
需要“日期”
需要“路径名”
如果ARGV.length!=4.
$stderr.print“用法:#{$0}-d |-h |-m |-s时间表达式日志文件\n”
出口1
结束
开始
总金额=整数ARGV[1]
挽救错误
$stderr.print“错误:参数'time'必须是整数\n”
$stderr.print“用法:#{$0}-d |-h |-m |-s时间表达式日志文件\n”
结束
如果ARGV[0]=“-m”
差距=合理(6086400)
time_str=“%b%d%H:%M”
elsif ARGV[0]=“s”
差距=合理(186400)
time_str=“%b%d%H:%M:%S”
elsif ARGV[0]=“-h”
差距=合理(360086400)
time_str=“%b%d%H”
elsif ARGV[0]=“d”
time_str=“%b%d”
差距=1
其他的
$stderr.print“用法:#{$0}-d |-h |-m |-s时间表达式日志文件\n”
出口1
结束
pn=路径名。新建(ARGV[3])
是否存在pn?
日志=(pn.目录?)?ARGV[3]+“/*”:ARGV[3]
其他的
$stderr.print“error:file'”这是一个很好的工具
从-10到现在,范围是您想要的任何范围
sed -n "/^$(date --date='10 minutes ago' '+%b %_d %H:%M')/,\$p" /var/log/blaaaa
您想要实际时间的最后10分钟的日志消息,还是相对于日志末尾的最后10分钟的日志消息?这种类型的内容在普通shell中变得很混乱——特别是因为您必须为解决方案使用的日期命令因系统而异。我可以用Perl给你一个答案吗?如果没有,我会给你一个适用于BSD的(我有一个Mac),你必须为Linux找到它(如果你有)。bash现在提供了很多强大的技巧来实现这类技巧。。。(见我的答案)。无论如何,perl仍然是这类工作的首选。@tripleee这不是真正的重复,因为目标是在文件结束前读取大量时间。另一个问题代表一个日志文件中的时间间隔。@FHauri没有结束条件只是同一问题的一个简单例子,不是吗?如果时间戳中有不同的月份呢?我认为字符串比较可能会失败。e、 g.[“Jan 18 10:27:32”<“Feb 18 10:27:32”]&&echo“older”
和[“Feb 18 10:27:32”<“Mar 18 10:27:32”]&&echo“older”
给出了不一致的结果。@DigitalTrampion True,如果时间段涵盖了月份的变化,我的解决方案将不起作用。您的解决方案更准确,我向您投了赞成票。@janos新的bash版本通过使用printf“%(…)T”-1
提供了一个内置的date
函数。这比使用叉子记录日期要快得多。要使用日期的endianess属性,可以使用关联数组更正月份条目。看看我的答案@好的,我投你一票;-)我想知道为什么它会返回以下内容:./test.sh:第8行:[:-gt:一元运算符预期日期:无效日期[pid 26481 on./test.sh:第8行:[:-gt:一元运算符预期日期:无效日期[pid 17563 on./test.sh:第8行:[:-gt:一元运算符预期12月18日10:19:16 Dec]
#!/usr/bin/perl -w
use strict;
use Date::Parse;
my $ref; # The only variable I will use in this.
open IN,"<".$ARGV[0]; # Open (READ) file submited as 1st argument
seek IN,-200,2; # Jump to 200 character before end of logfile. (This
# could not suffice if log file hold very log lines! )
while (<IN>) { # Until end of logfile...
$ref=str2time($1) if /^(\S+\s+\d+\s+\d+:\d+:\d+)/;
}; # store time into $ref variable.
seek IN,0,0; # Jump back to the begin of file
while (<IN>) {
print if /^(.{15})\s/&&str2time($1)>$ref-600;
}
#!/bin/bash
declare -A month
for i in {1..12};do
LANG=C printf -v var "%(%b)T" $(((i-1)*31*86400))
month[$var]=$i
done
printf -v now "%(%s)T" -1
printf -v ref "%(%m%d%H%M%S)T" $((now-600))
while read line;do
printf -v crt "%02d%02d%02d%02d%02d" ${month[${line:0:3}]} \
$((10#${line:4:2})) $((10#${line:7:2})) $((10#${line:10:2})) \
$((10#${line:13:2}))
# echo " $crt < $ref ??" # Uncomment this line to print each test
[ $crt -gt $ref ] && break
done
cat
cat >last10min.sh
chmod +x last10min.sh
sudo cat /var/log/syslog | ./last10min.sh
#!/bin/bash
declare -A month
for i in {1..12};do
LANG=C printf -v var "%(%b)T" $(((i-1)*31*86400))
month[$var]=$i
done
read now < <(date -d "$(tail -n1 $1|head -c 15)" +%s)
printf -v ref "%(%m%d%H%M%S)T" $((now-600))
export -A month
{
while read line;do
printf -v crt "%02d%02d%02d%02d%02d" ${month[${line:0:3}]} \
$((10#${line:4:2})) $((10#${line:7:2})) $((10#${line:10:2})) \
$((10#${line:13:2}))
[ $crt -gt $ref ] && break
done
cat
} <$1
recentLog(){
perl -MDate::Parse -ne '
print if/^(.{'${3:-15}'})\s/ &&
str2time($1)>time-'$((
60*${2:-10}
)) ${1:-/var/log/daemon.log}
}
#! /usr/bin/env ruby
require 'date'
require 'pathname'
if ARGV.length != 4
$stderr.print "usage: #{$0} -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: #{$0} -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: #{$0} -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: #{$0} -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
sed -n "/^$(date --date='10 minutes ago' '+%b %_d %H:%M')/,\$p" /var/log/blaaaa