首先声明这次awk用途,是从一个nginx的access_log中抽取一些关键字,进行访问次数的排序。希望实现的功能很简单,但是日志文件非常庞大,文件大小会超过40G。
步骤一:
在用awk进行解析的时候,报错
awk: (FILENAME=- FNR=4894190) fatal: str2wstr: *ptr: can't allocate 676 bytes of memory (Cannot allocate memory)
也就是说程序内存控制出了问题,有未释放的内容,积累起来出现问题。
代码如下:
awk -F\" '{ if( match($2, "kfuin=([0-9]+)") ) print substr($2,RSTART+6,RLENGTH-6)}' log_file > aaa.txt
步骤二:
cat log_file | awk -F\" '{ if( match($2, "kfuin=([0-9]+)") ) print substr($2,RSTART+6,RLENGTH-6)}' > aaa.txt
这种方式会引发同类型的错误:awk: (FILENAME=- FNR=4892857) fatal:
Memory exhausted
写一个最简单的awk来验证
awk -F\" '{ print $1 }' > aaa.txt
用top命令查看,内存占用几乎为0,而且不会增长。由此判断很有可能awk调用方式的问题。
在google搜索相应内容,有人可能是match函数问题,如果在函数中使用match函数,会引发类似问题。链接地址:http://objectmix.com/awk/115064-memory-exhausted-error-when-match-function-called-two-different-regexp.html
但是显然不是希望的答案,尝试按照里面的方式给正则表达式赋值,和预期一样,问题依然存在。
用man命令,查看match函数的文档
match(s, r [, a])
返回匹配正则表达式r在s中的位置,如果不存在返回0,会将位置和长度信息赋值给RSTART和RLENGTH变量。注意参数顺序与~操作符一样。str ~ re。如果传入第三个数组,a的值会覆盖,将匹配的圆括号中的表达式,从1到n填充给a。a的第0个元素,完整匹配正则r的部分字符串s
步骤三:
尝试使用match函数的第三个参数进行改造
awk -F\" ' match($2, /kfuin=([0-9]+)/, matches) { print matches[1] }' log_file > aaa.txt
运行起来,一切正常。
分析:
调用substr产生问题,推断不能在循环中使用substr,结论还有后续验证。
--------------------------------------------------------------------------------------------------------------------------------------------
网上有人分析过sed, awk, head分析大文件的效率。awk效率最高,其次为head,sed效率最低。
[root@file data1]# time sed -n '31268618,33573328p' design.acl >/dev/null
real 1m15.584s
user 1m6.727s
sys 0m0.880s
[root@file data1]# time awk 'NR>=31268618;NR==33573328{exit}' design.acl >/dev/null
real 0m29.460s
user 0m14.713s
sys 0m0.938s
[root@file data1]# time head -33573328 design.acl | tail -31268618 >/dev/null
real 1m8.819s
user 0m3.761s
sys 0m5.090s
好的工具还是要正确使用