如何在正则表达式中使用awk变量?

问题描述 投票:23回答:4

我有一个名为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

然后,因为我刚开始编写脚本

有没有更好的方法来解决我的问题?

regex awk
4个回答
30
投票

如果你不使用awk正则表达式标记,//可以匹配变量。

if ( $0 ~ regex ){ print $0; }

在这种情况下,将所需的正则表达式构建为字符串

regex = dom"$"

然后匹配regex变量

if ( $1 ~ regex ) {
  domain[dom]+=$2;
}

18
投票

首先,变量是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 

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

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
© www.soinside.com 2019 - 2024. All rights reserved.