awk 输入中用引号括起来的字段

awk 输入中用引号括起来的字段

我正在尝试用 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 脚本看起来与上面的非常相似!)

相关内容