假设我有一个日志文件mylog
这样的:如何用awk轻松过滤日志?
[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
而且我想找到那些在18.00和10月1日之间发生的1.00 11月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
我设法用match()
然后mktime()
时代到时间戳转换。首先找到指定的模式,该模式存储在数组a[]
中,以便可以访问它(有趣的是,glenn jackman的回答为access captured group from line pattern为一个很好的例子)。由于mktime
需要格式YYYY MM DD HH MM SS[ DST]
,我还必须将月份以Xxx
的形式转换为数字,我使用an answer by Ed Morton to "convert month from Aaa to xx":awk '{printf "%02d\n",(match("JanFebMarAprMayJunJulAugSepOctNovDec",$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
然而,对于那些应该更直截了当的事情来说,这似乎是相当多的工作。尽管如此,在man gawk
引入“时间函数”一节的是
由于AWK程序的主要用途之一是处理包含时间戳信息的日志文件 ,GAWK提供了用于获得时间戳以下 功能并格式化它们。
所以我想知道:有没有更好的方法来做到这一点?例如,如果格式代替dd/Mmm/YYYY:HH:MM:ss
类似于dd Mmm YYYY HH:MM:ss
?难道不可能在外部提供匹配模式,而不必在每次发生这种情况时都改变它?我真的必须使用match()
,然后处理该输出,然后输入mktime()
? gawk
不提供更简单的方法来做到这一点?
您好,我不熟悉awk或gawk,来到这里是因为正则表达式标签,并找到您的问题有趣。我熟悉.bat编程,在这种情况下,我们使用操作系统定义的变量来处理这种事情。是否有可能将环境变量与参数混合到awk中? –
@JorgeCampos感谢您的评论。是的,在'awk'中你可以使用环境变量。例如,你可以说'awk -v myvar =“$ shell_var”'BEGIN {print myvar}''打印一个shell变量。请参阅'-v'的用法来传递它。 – fedorqui
难道这不是您的问题的解决方案吗?当然,如果没有更好的办法。 –