我一直在为这个问题苦恼,希望有一个简单的解决方案,但我可能错过了。
摘要
简化后的以下代码无法处理解析到其中的IPv6地址。我应该在解析到AWK之前对变量进行SED操作,还是可以更改AWK正则表达式以仅匹配$clog中每行的第一个“:”?
$ clog='djerk.nl:80 200.87.62.227 - - [20/Nov/2015:01:06:25 +0100] "GET /some_url HTTP/1.1" 404 37252
bogus.com:80 200.87.62.227 - - [20/Nov/2015:01:06:27 +0100] "GET /some_url HTTP/1.1" 404 37262
djerk.nl:80 200.87.62.227 - - [20/Nov/2015:01:06:29 +0100] "GET /another_url HTTP/1.1" 200 11142
ipv6.com:80 2a01:3e8:abcd:320::1 - - [20/Nov/2015:01:35:24 +0100] "GET /some_url HTTP/1.1" 200 273'
$ echo "$clog" | awk -F '[: -]+' '{ vHost[$1]+=$13 } END { for (var in vHost) { printf "%s %.0f\n", var, vHost[var] }}'
> bogus.com 37262
> djerk.nl 48394
> ipv6.com 0
可以看到变量$clog的最后一行,捕获了虚拟主机域名,但字节数应该为273而不是0。 原始复杂问题: 我遇到的问题与“:”字符有关。除了其他两个字符(空格和破折号)之外,我需要AWK仅匹配它正在评估的每行中第一个“:”出现的位置。下面通过三个字符拆分每行,这很好用,直到日志条目包含IPv6地址。
matrix=$( echo "$clog" | awk -F '[: -]+' '{ vHost[$1]++; Bytes[$1]+=$13 } END { for (var in vHost) { printf "%s %.0f %.0f\n", var, vHost[var], Bytes[var] }}' )
以上代码将转换以下日志条目(包含在变量 $clog 中):
djerk.nl:80 200.87.62.227 - - [20/Nov/2015:01:06:25 +0100] "GET /some_url HTTP/1.1" 404 37252 "-" "Safari/11601.1.56 CFNetwork/760.0.5 Darwin/15.0.0 (x86_64)"
bogus.com:80 200.87.62.227 - - [20/Nov/2015:01:06:27 +0100] "GET /some_url HTTP/1.1" 404 37262 "-" "Safari/11601.1.56 CFNetwork/760.0.5 Darwin/15.0.0 (x86_64)"
djerk.nl:80 200.87.62.227 - - [20/Nov/2015:01:06:29 +0100] "GET /wordpress/2014/ssl-intercept-headaches HTTP/1.1" 200 11142 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B410 Safari/600.1.4"
djerk.nl:80 200.87.62.227 - - [20/Nov/2015:01:06:30 +0100] "GET /some_other_url HTTP/1.1" 404 37264 "-" "Safari/11601.1.56 CFNetwork/760.0.5 Darwin/15.0.0 (x86_64)"
将其转换为类似下面的表格,包含虚拟主机名称(不包括TCP端口号)、点击量和累积字节数。每个虚拟主机一行:
djerk.nl 3 85658
bogus.com 1 37262
但是由于IPv6地址的表示方式,它们会被无意中分割,导致AWK在评估这些日志条目时产生虚假输出。示例IPv6日志条目:
djerk.nl:80 2a01:3e8:abcd:320::1 - - [20/Nov/2015:01:35:24 +0100] "POST /wordpress/wp-cron.php?doing_wp_cron=*** HTTP/1.0" 200 273 "-" "WordPress; http://www.djerk.nl/wordpress"
我想一个解决办法是对变量 $clog 进行处理,替换第一次出现的 ":" 并从 AWK 正则表达式中删除该字符。但我认为原生的 bash 字符串替换无法处理多行变量。
clog=$(sed 's/:/ /' <<< "$clog")
matrix=$( echo "$clog" | awk -F '[ -]+' '{ vHost[$1]++; Bytes[$1]+=$10 } END { for (var in vHost) { printf "%s %.0f %.0f\n", var, vHost[var], Bytes[var] }}' )
这是因为$clog被引用,保留了换行符,并在每行上单独运行sed。结果(如所示),需要调整AWK行以忽略“:”,并抓取$10而不是$13的字节计数。
所以事实证明,在编写本文时,我已经给自己找到了一个解决方案。但我相信有人会知道更好、更有效的方法。
$1,$13
,你会发现问题即使没有IPv6地址也会出现。 - undefined$13
中。 - undefined