Regex 如何使用awk轻松过滤日志?
假设我有一个日志文件Regex 如何使用awk轻松过滤日志?,regex,date,awk,timestamp,gawk,Regex,Date,Awk,Timestamp,Gawk,假设我有一个日志文件mylog,如下所示: [01/Oct/2015:16:12:56 +0200] error number 1 [01/Oct/2015:17:12:56 +0200] error number 2 [01/Oct/2015:18:07:56 +0200] error number 3 [01/Oct/2015:18:12:56 +0200] error number 4 [02/Oct/2015:16:12:56 +0200] error number 5 [10/Oct/
mylog
,如下所示:
[01/Oct/2015:16:12:56 +0200] error number 1
[01/Oct/2015:17:12:56 +0200] error number 2
[01/Oct/2015:18:07:56 +0200] error number 3
[01/Oct/2015:18:12:56 +0200] error number 4
[02/Oct/2015:16:12:56 +0200] error number 5
[10/Oct/2015:16:12:58 +0200] error number 6
[10/Oct/2015:16:13:00 +0200] error number 7
[01/Nov/2015:00:10:00 +0200] error number 8
[01/Nov/2015:01:02:00 +0200] error number 9
[01/Jan/2016:01:02:00 +0200] error number 10
我想找出那些发生在10月1日18点到11月1日1点之间的线。也就是说,预期产出将是:
[01/Oct/2015:18:07:56 +0200] error number 3
[01/Oct/2015:18:12:56 +0200] error number 4
[02/Oct/2015:16:12:56 +0200] error number 5
[10/Oct/2015:16:12:58 +0200] error number 6
[10/Oct/2015:16:13:00 +0200] error number 7
[01/Nov/2015:00:10:00 +0200] error number 8
我已经通过使用and then将时间转换为时间戳。第一个查找指定的模式,该模式存储在数组a[]
中,因此可以访问该模式(有趣的是,可以看到glenn jackman的答案,这是一个很好的示例)。由于mktime
需要格式YYYY-MM-DD HH-MM-SS[DST]
,因此我还必须将格式为Xxx
的月份转换为一个数字,我使用:awk'{printf”%02d\n',(match(“janfebmaraprmayjunjunaugsepoctnovdec”、$0)+2)/3}
最后,我在变量mytimestamp
中得到了时间戳:
awk 'match($0, /([0-9]+)\/([A-Z][a-z]{2})\/([0-9]{4}):([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}) ([+-][0-9]{4})/, a) {
day=a[1]; month=a[2]; year=a[3];
hour=a[4]; min=a[5]; sec=a[6]; utc=a[7];
month=sprintf("%02d",(match("JanFebMarAprMayJunJulAugSepOctNovDec",month)+2)/3);
mydate=sprintf("%s %s %s %s %s %s %s", year,month,day,hour,min,sec,utc);
mytimestamp=mktime(mydate)
print mytimestamp
}' mylog
返回:
1443708776
1443712376
1443715676
等等
所以现在我准备根据给定的日期进行转换。由于awk
处理这种格式需要很多时间,因此我更喜欢通过一个外部shell变量提供它们,使用date-d“my date”+“%s”
打印时间戳:
start="$(date -d"1 Oct 2015 18:00 +0200" +"%s")"
end="$(date -d"1 Nov 2015 01:00 +0200" +"%s")"
总而言之,这是有效的:
awk start="$(date -d"1 Oct 2015 18:00 +0200" +"%s")" end="$(date -d"1 Nov 2015 01:00 +0200" +"%s")" 'match($0, /([0-9]+)\/([A-Z][a-z]{2})\/([0-9]{4}):([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}) ([+-][0-9]{4})/, a) {day=a[1]; month=a[2]; year=a[3]; hour=a[4]; min=a[5]; sec=a[6]; utc=a[7]; month=sprintf("%02d",(match("JanFebMarAprMayJunJulAugSepOctNovDec",month)+2)/3); mydate=sprintf("%s %s %s %s %s %s %s", year,month,day,hour,min,sec,utc); mytimestamp=mktime(mydate); if (start<=mytimestamp && mytimestamp<=end) print}' mylog
[01/Oct/2015:18:07:56 +0200] error number 3
[01/Oct/2015:18:12:56 +0200] error number 4
[02/Oct/2015:16:12:56 +0200] error number 5
[10/Oct/2015:16:12:58 +0200] error number 6
[10/Oct/2015:16:13:00 +0200] error number 7
[01/Nov/2015:00:10:00 +0200] error number 8
(日期-d”日期-d”日期-d“日期-d”1-2015年11月1-2015年11月1-2015年11月1-11月15:00+02000+00+0.00+0.00+0.00+0+0.00+0.00+0+0.00+0+0.00+0+0.00+0+0.5““”””””””””””””””””””””””””””))比赛(比赛(0)比赛((0,)比赛(0,(0,(0,/,(0,/,(0,/,(0,/,(0,/(,(0,/([0-0,/([0-0-0-0-0-0-9[0-9[0-9[0-9[0-9[0-9[0-9[0-9[0-9-9[0-9[0-9[0-9[0-9[0-时间=A[5];秒=A[6];utc=A[7];月份=sprintf(“%02d”),(匹配(“Janfebmarapramayjunjulaugsepoctnovdec”,月)+2)/3);mydate=sprintf(“%s%s%s%s%s%s”,年、月、日、小时、分钟、秒、utc);mytimestamp=mktime(mydate);如果(开始不进入时间格式(假设所有记录的格式都相同),您可以使用
排序| awk
组合轻松实现同样的效果
这假设日志没有排序,根据您的格式和特殊排序选项来排序月份(M
)和awk来选择感兴趣的范围。排序基于年、月和日的顺序
$ sort -k1.9,1.12 -k1.5,1.7M -k1.2,1.3 log | awk '/01\/Oct\/2015/,/01\/Nov\/2015/'
如果文件已经排序,您可以轻松地扩展到包含时间,并删除排序
以下内容也有时间限制
awk -F: '/01\/Oct\/2015/ && $2>=18{p=1}
/01\/Nov\/2015/ && $2>=1 {p=0} p'
我会在
awk
中使用date
命令来实现这一点,但不知道这将如何处理大型日志文件
awk -F "[][]" -v start="$(date -d"1 Oct 2015 18:00 +0200" +"%s")"
-v end="$(date -d"1 Nov 2015 01:00 +0200" +"%s")" '{
gsub(/\//,"-",$2);sub(/:/," ",$2);
cmd="date -d\""$2"\" +%s" ;
cmd|getline mytimestamp;
close(cmd);
if (start<=mytimestamp && mytimestamp<=end) print
}' mylog
awk-F“[]”-v start=“$(日期-d”2015年10月1日18:00+0200”+“%s”)”
-v end=“$(日期-d”2015年11月1日01:00+0200”+“%s”)”{
gsub(/\/,“-”,$2);sub(/:/,”,$2);
cmd=“日期-d\”“$2\”“+%s”;
cmd | getline mytimestamp;
关闭(cmd);
如果(开始使用ISO 8601时间格式!
然而,这似乎是一个相当多的工作,应该更直接的东西
是的,这应该很简单,之所以不简单,是因为日志不使用。应用程序日志应使用ISO格式和UTC来显示时间,其他设置应被视为已中断并已修复
您的请求应分为两部分。第一部分规范日志,将日期转换为ISO格式,第二部分执行研究:
awk '
match($0, /([0-9]+)\/([A-Z][a-z]{2})\/([0-9]{4}):([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}) ([+-][0-9]{4})/, a) {
day=a[1]
month=a[2];
year=a[3]
hour=a[4]
min=a[5]
sec=a[6]
utc=a[7];
month=sprintf("%02d", (match("JanFebMarAprMayJunJulAugSepOctNovDec",month)+2)/3);
myisodate=sprintf("%4d-%2d-%2dT%2d:%2d:%2d%6s", year,month,day,hour,min,sec,utc);
$1 = myisodate
print
}' mylog
ISO 8601日期的好处在于——除了作为标准日期之外——时间顺序与词典顺序一致,因此,您可以使用/…/,/…/
操作符提取您感兴趣的日期。例如,要查找2015年10月1日18:00+0200和2015年11月1日01:00+0200之间发生的事情,请添加将以下过滤器添加到上一个标准化过滤器:
awk '/2015-10-01:18:00:00+0200/,/2015-11-01:01:00:00+0200/'
大家好,我不熟悉awk或gawk,来这里是因为regex标记和发现您的问题很有趣。我熟悉.bat编程,在这种情况下,我们使用操作系统定义的变量来实现这类功能。是否可以将环境变量与awk的参数混合使用?@JorgeCampos感谢注释。是的,在awk
中可以使用环境变量。例如,可以说awk-v myvar=“$shell_var””开始{print myvar}“
来打印shell变量。请参阅使用-v
来传递它。这不是解决您问题的方法吗?当然,如果没有更好的方法。@JorgeCampos mmm是的,这实际上是我的问题之一:我可以在匹配()外部提供这样的日期格式参数吗
函数?根据文档,不,你不能。我看到的唯一方法是使用外部变量。但正如我所说,我不是awk专家。也许其他人知道一种方法!请注意,这比我在问题中使用的方法更不通用,也非常具体。我的意思是,它有效,我感谢你的努力,但没有帮助概括这个问题,并提供一个很好的工具来过滤具有给定格式且在两个给定日期时间内的日志。为什么需要使用两种不同的时间格式?如果您可以在日志中使用相同的格式,那么脚本将是微不足道的。请您回答我的这个问题。我有一个公开的悬赏,价值100美元:)我的日志文件中的日期格式有点不同。我尝试从这个问题中给出的日期格式开始,创建一个日志文件,内容与问题中给出的内容相同,并尝试像这样运行awk
命令-awk
,但我没有得到任何输出。