我有一个名为domain的文件,其中包含一些域名。例如:
google.com
facebook.com
...
yahoo.com
我有另一个名为site的文件,其中包含一些网站的URL和数字。例如:
image.google.com 10
map.google.com 8
...
photo.facebook.com 22
game.facebook.com 15
..
现在我要计算每个域名的网址号。例如:google.com有10 + 8。所以我写了一个像这样的awk脚本:
BEGIN{
while(getline dom < "./domain" > 0) {
domain[dom]=0;
}
for(dom in domain) {
while(getline < "./site" > 0) {
if($1 ~/$dom$) #if $1 end with $dom {
domain[dom]+=$2;
}
}
}
}
但代码if($1 ~/$dom$)
并不像我想的那样运行。因为正则表达式中的变量$ dom是按字面解释的。所以,第一个问题是:
有没有办法在正则表达式中使用变量$dom
?
然后,因为我刚开始编写脚本
有没有更好的方法来解决我的问题?
如果你不使用awk
正则表达式标记,//
可以匹配变量。
if ( $0 ~ regex ){ print $0; }
在这种情况下,将所需的正则表达式构建为字符串
regex = dom"$"
然后匹配regex
变量
if ( $1 ~ regex ) {
domain[dom]+=$2;
}
首先,变量是dom
而不是$dom
- 考虑$
作为运算符来提取存储在变量dom
中的列号的值
其次,awk不会插入//
之间的内容 - 那只是一个字符串。
你想要match()
函数,其中第二个参数可以是一个被视为正则表达式的字符串:
if (match($1, dom "$")) {...}
我会编写一个解决方案,如:
awk '
FNR == NR {domain[$1] = 0; next}
{
for (dom in domain) {
if (match($1, dom "$")) {
domain[dom] += $2
break
}
}
}
END {for (dom in domain) {print dom, domain[dom]}}
' domain site
使用awk
脚本的一种方法:
BEGIN {
FS = "[. ]"
OFS = "."
}
FNR == NR {
domain[$1] = $0
next
}
FNR < NR {
if ($2 in domain) {
for ( i = 2; i < NF; i++ ) {
if ($i != "") {
line = (line ? line OFS : "") $i
}
}
total[line] += $NF
line = ""
}
}
END {
for (i in total) {
printf "%s\t%s\n", i, total[i]
}
}
运行如下:
awk -f script.awk domain.txt site.txt
结果:
facebook.com 37
google.com 18
您显然想要阅读site
文件一次,而不是每次在domain
中读取一次。但是,修复它是微不足道的。
同样,awk
中的变量(除了字段$0
... $9
等)不以$
为前缀。特别是,$dom
是由变量dom
标识的字段编号(通常,这将是0
,因为域字符串不会转换为任何其他数字)。
我认为您需要找到一种方法从site
文件中读取数据来获取域。我不确定您是否需要处理具有国家域名的网站,例如bbc.co.uk
以及GTLD中的网站(google.com
等)。假设您没有处理国家/地区域名,可以使用以下命令:
BEGIN {
while (getline dom < "./domain" > 0) domain[dom] = 0
FS = "[ .]+"
while (getline < "./site" > 0)
{
topdom = $(NF-2) "." $(NF-1)
domain[topdom] += $NF
}
for (dom in domain) print dom " " domain[dom]
}
在第二个while
循环中,有NF
字段; $NF
包含计数,$1
.. $(NF-1)
包含域的组成部分。因此,topdom
最终包含顶级域名,然后用于索引到第一个循环中初始化的数组。
给定问题中的数据(减去点的线),输出为:
yahoo.com 0
facebook.com 37
google.com 18