awk 小结

原文:  http://blog.romebuilder.com/2011/10/521/

1.处理时间

日志中的时间格式多为 2011-09-30 00:00:00,035 ,有时,我需要对日志中给定的时间段进行数据分析,这时就要对每条日志记录的时间做对比。但是如何来高效地比较时间呢?

我的想法是,将时间字条窜转化为unix timestamp,在Awk中实现这种转换有两种方式,一种是调用shell命令,date;另一种是使用内置的mktime.

下面是调用shell 命令 date

egrep -i "<—.*login" connector.log | awk -F ' ' '
BEGIN{
    restartTimeStr = "2011-09-21 09:43:28,367"
    "date +%s -d ""\""restartTimeStr"\""|getline restartTimestamp
    printf("Server restarted at %s, timestamp is %s\n", restartTimeStr, restartTimestamp)
    before = "before"
    after = "after"
}
{
    split($0, rowArr); dateStr = $1" "$2;
    "date +%s -d ""\""dateStr"\""|getline timestamp;
   
    if(timestamp < restartTimestamp) addrMap[$7][before]++;
    else if(timestamp > restartTimestamp) addrMap[$7][after]++;
}
END{
    for(addr in addrMap) printf "Address: %s , before: %s , after : %s\n", addr,addrMap[addr][before], addrMap[addr][after]
}'

这种做法存在的问题是,当你的日志文件非常大时,如10G+时,这段就可能出问题。系统可能会提示里,文件句柄用完。因为在调用shell命令时,awk可能会新开一个管道用于与shell通信。

那么,下面来说说使用mktime(注:这个内置函数好像只在gawk里面,对于awk的多种版本,我还不太了解).

egrep -i "<—.*login" connector.log | awk -F ' ' '
BEGIN{
    restartTimeStr = "2011-09-21 09:43:28,367"
    "date +%s -d ""\""restartTimeStr"\""|getline restartTimestamp
    printf("Server restarted at %s, timestamp is %s\n", restartTimeStr, restartTimestamp)
    before = "before"
    after = "after"
}
{
    split($0, rowArr); dateStr = $1" "$2; /* dateStr format like:  2011-09-30 10:15:17,333*/
   
    /*split the date str*/
    split(dateStr, dateStrArr, "[\\- :]");
    dateStr = ""
    for(i=1;i<=length(dateStrArr);i++) dateStr = dateStr" "dateStrArr[i]
    /* now date str format like: 2011 09 30 10 15 17,333*/
    timestamp = mktime(dateStr)

   
    if(timestamp < restartTimestamp) addrMap[$7][before]++;
    else if(timestamp > restartTimestamp) addrMap[$7][after]++;
}
END{
    for(addr in addrMap) printf "Address: %s , before: %s , after : %s\n", addr,addrMap[addr][before], addrMap[addr][after]
}'

mktime 让人不爽的地方时,它只接受(YY MM DD HH mm SS)这样的参数格式,用户好像无法指定传入的参数格式。因此,在调用这个函数之前,我们必需将日期先进行解析。另外,要注意的一点是,在使用awk的 for语句时,for(var in array)好像是乱序输出结果,那么对于这个顺序敏感的——如这个日期的顺序——就需要按索引来读取了。

虽然mktime用起来比较难看,但是,就上面两段代码而言,后者的速度要比前者快上好几倍。

2.排序

awk的内置的排序函数,但还没有搞清楚怎么用才合适,因些,我就将结果输出后,用shell的sort命令来排序。在我遇到的情况中,一般都不需要在代码的处理过程中使用排序,而是在得到处理结果后排序,所以使用shell sort也比较合适。

egrep -i "<—.*login" connector.log | awk -F '[' '{addr = substr($5, 0, index($5, "->") - 1); addrMap[addr]++} END{ for(addr in addrMap) printf "%s %s\n", addr,addrMap[addr]}' | sort -k2 -n -r | head -20

3.待续

你可能感兴趣的:(awk 小结)