我有一个名为域的文件,其中包含一些域名。例如:
google.com
facebook.com
...
yahoo.com
我还有另一个名为网站的文件,其中包含一些网站网址和数字。例如:
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
?
然后,因为我刚开始编写脚本
有没有更好的方法来解决我的问题?
答案 0 :(得分:30)
awk
正则表达式标记, //
可以与变量匹配。
if ( $0 ~ regex ){ print $0; }
在这种情况下,将所需的正则表达式构建为字符串
regex = dom"$"
然后匹配regex
变量
if ( $1 ~ regex ) {
domain[dom]+=$2;
}
答案 1 :(得分:18)
首先,变量为dom
而非$dom
- 将$
视为运算符,以提取存储在变量dom
<中的列号的值/ p>
其次,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
答案 2 :(得分:1)
使用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
答案 3 :(得分:1)
您显然希望一次阅读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
答案 4 :(得分:0)
上述答案的问题是,如果您使用字符串而不是正则表达式/.../,则不能使用“元字符”(例如\ <表示单词开头的单词边界)。 如果您有一个域xyz.com以及两个站点ab.xyz.com和cd.prefix_xyz.com,则两个站点条目的编号将被添加到xyz.com
这是使用awk的管道和sed命令的解决方案: ...
for(dom in domain) {
while(getline < "./site" > 0) {
# let sed replaces occurence of the domain at the end of the site
cmd = "echo '" $1 "' | sed 's/\\<'" dom "'$/NO_VALID_DOM/'"
cmd | getline x
close(cmd)
if (match(x, "NO_VALID_DOM")) {
domain[dom]+=$2;
}
}
close("./site") # this misses in original code
}
...