假设我有一个这样的日志文件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: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
然而,对于应该更直接的事情,这似乎是相当多的工作。尽管如此,引入了&#34;时间功能&#34; man gawk
中的部分是
由于AWK程序的主要用途之一是处理日志文件 包含时间戳信息的gawk提供以下内容 用于获取时间戳和格式化它们的函数。
所以我想知道:有没有更好的方法呢?例如,如果格式而不是dd/Mmm/YYYY:HH:MM:ss
类似dd Mmm YYYY HH:MM:ss
,该怎么办?无法在外部提供匹配模式,而不是每次都发生这种情况时都需要更改匹配模式吗?我是否真的必须使用match()
,然后处理该输出然后输入mktime()
?不是gawk
提供了一种更简单的方法吗?
答案 0 :(得分:2)
然而,对于一些应该更直接的事情来说,这似乎是相当有用的工作。
是的,这应该是直截了当的,原因不是,因为日志不使用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/'
答案 1 :(得分:0)
没有进入时间格式(假设所有记录的格式相同),您可以使用sort | 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'
答案 2 :(得分:0)
我会在awk
内使用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
命令来实现这一点,但不知道这对大型日志文件的执行方式。
// Query the Core Reporting API from Google Analytics with the defined variables
function requestResponse() {
gapi.client.analytics.data.ga.get({
'ids': 'ga:' + $('input[name="hiddenProfileId"]').val(),
'start-date': $('input[name="hiddenStartDate"]').val(),
'end-date': $('input[name="hiddenEndDate"]').val(),
'metrics': metricsArrayOutput.join(","),
'dimensions': dimensionsArrayOutput.join(",")
// If response isn't an error, then change div background to pale green and show a "Tree View" of the JSON obtained
}).then(function(response) {
$("#responseOutput").empty();
$("#responseOutput").JSONView(response.result, {collapsed: true});
$("#responseOutput").css("background-color", "#bef7be");
// Handle error: change div background to pale red and show the error Objects of the JSON obtained
}, function(errorResponse) {
$("#responseOutput").empty();
$("#responseOutput").JSONView(errorResponse.result.error, {collapsed: false});
$("#responseOutput").css("background-color", "#FBDDDD");
alert("bad things happen to everyone");
})
}