我正在尝试用 awk 处理网络服务器日志文件。例如
123.222.333.444 - - [24/Feb/2015:13:09:19 +0100] "GET / HTTP/1.1" 200 15852 "https://www.google.dk/" "Mozilla/5.0 (Windows NT 6.1) ...."
- 字段 1、2、3 仅由空格分隔。
- 字段 4,日期用 [] 括起来
- 字段 5 是网址,用“”括起来
- 字段 6,7 仅由空格分隔。(整数)
- 字段 8,9 referer 和 useragent 括在“”中
我该如何解析这些字段?
答案1
我将选择一个“主要”分隔符,并split()
在某些字段中使用:
awk -F '"' '
{
http_cmd = $2
url = $4
ua = $6
split($1, a, /[][]/); date = a[2]
split(a[1], b, " "); ip = b[1]; f2 = b[2]; f3 = b[3]
split($3, c, " "); code = c[1]; size = c[2]
OFS = "\n"
print ip, f2, f3, date, http_cmd, code, size, url, ua
}' << END
123.222.333.444 - - [24/Feb/2015:13:09:19 +0100] "GET / HTTP/1.1" 200 15852 "https://www.google.dk/" "Mozilla/5.0 (Windows NT 6.1) ...."
END
123.222.333.444
-
-
24/Feb/2015:13:09:19 +0100
GET / HTTP/1.1
200
15852
https://www.google.dk/
Mozilla/5.0 (Windows NT 6.1) ....
答案2
另一个解决方案是解析日志:
function consume(pat) {
sub(/^[ \t]+/, "") # strip leading whitespace
if (!match($0, pat)) return
s = substr($0, p, RLENGTH) # extract part matching regex pattern
$0 = substr($0, RSTART + RLENGTH + 1) # strip matched part
return s
}
BEGIN {
# regular expressions to match ...
nonblank = "[^ \t]+" # a sequence of non-whitespace characters
quoted_string = "\"[^\"]+\"" # a ""-quoted string
bracketed_string = "\\[[^]]+\\]" # a []-quoted string
}
{ print
array["ip"] = consume(nonblank)
array["identity"] = consume(nonblank)
array["userid"] = consume(nonblank)
array["time"] = consume(bracketed_string)
array["request"] = consume(quoted_string)
array["status"] = consume(nonblank)
array["size"] = consume(nonblank)
array["referer"] = consume(quoted_string)
array["agent"] = consume(quoted_string)
for (key in array) printf " %10s: %s\n", key, array[key]
}
请注意,嵌入的引号将使解析器无法正常工作。还有其他改进需要进行,但我希望您能理解我的想法。
不过,我认为,如果您需要更多功能,最好查看专用的日志文件解析器或更强大的脚本语言。例如,Perl 有一个模块文字::平衡它可以提取带引号和括号的字符串,并且通常可以正确处理嵌入的引号和其他困难。(顺便说一句,使用 Text::Balanced 的 Perl 脚本看起来与上面的非常相似!)