AWK问题:计算“不匹配”

问题描述

我想计算文件中某些单词的出现次数。然后,我修改我的代码以另外计算与任何单词不匹配的行数。

例如,这是我的输入文件(test.txt):

select  title 
from    books
where   regexp_count(title,'\w+') > 2

这是我的代码

fred
fred
fred
bob
bob
john
BILL
BILL

这很好用,并给了我这个输出

awk '
    /fred/ { count["fred"]++ }
    /bob/ { count["bob"]++ }
    /john/ { count["john"]++ }
   END      { for (name in count) print name,"was found on",count[name],"lines." }
   ' test.txt

现在,我想计数不匹配的行,所以我做了以下代码

john was found on 1 lines.
bob was found on 2 lines.
fred was found on 3 lines.

在这样的if语句上遇到错误

awk '
    found=0
    /fred/ { count["fred"]++; found=1 }
    /bob/ { count["bob"]++; found=1 }
    /john/ { count["john"]++; found=1 }
    if (found==0) { count["none"]++ }
   END      { for (name in count) print name,"lines." }
   ' test.txt

有什么想法为什么不起作用?

解决方法

考虑到您要打印仅出现1次的行,请尝试以下操作。您无需为每个数组值定义相同的变量,因为它可能产生假阳性结果。因此最好从条件中检查数组值中的计数值。

awk '
/fred/{ count["fred"]++ }
/bob/{ count["bob"]++}
/john/{ count["john"]++}
END{
  for(name in count){
     if(count[name]==1){
       print name,"was found only 1 time ",name
     }
  }
}
'  Input_file

注意: 另外,对于您的语法错误,awk会先使用condition然后是action的方法,因此当条件为正确或错误,将按照以下说明执行所提到的动作:-> / test / {print“ something ....”}。在您的情况下,您直接提到的操作是为变量赋值,如果您使用{found=1},该变量将起作用,这只是为了回答语法错误部分。

,

关于使用条件,您有简单的语法错误。此声明无效:

awk 'if (found==0) { count["none"]++ }'  # syntax error

因为if ()并不构成可能在{}之外存在的条件。您应该使用以下任一方法:

awk '{ if (found==0) count["none"]++ }'

awk 'found==0{ count["none"]++ }'

脚本开头的found = 0也应放在{}内,因为它也是一条语句。以下是一些有用的链接:patterns可以位于{}的外部和前面,{}的内部可以是actions


您的脚本仅需进行必要的修改即可:

BEGIN { count["fred"]; count["bob"]; count["john"]; count["none"] }
{ found = 0 }
/fred/ { count["fred"]++; found=1 }
/bob/ { count["bob"]++; found=1 }
/john/ { count["john"]++; found=1 }
found==0{ count["none"]++ }
END { for (name in count) print name,"was found on",count[name]+0,"lines." }
  • 已纠正两个语法错误。
  • 添加了项目初始化,因为如果没有它,则如果根本没有“ fred”,则不会打印“ fred”的行。
  • 添加了count[name]+0,因此,如果item为空字符串,则将打印零。
,

有两种方法可以实现您想要的。 OP提出的方法虽然可行,但实际上并不灵活。我们假设您有一个字符串str,其中包含您感兴趣的单词:

awk -v str="fred bob john"                 \
    'BEGIN{split(str,b);for(i in b) a[b[i]]; delete b }
     ($0 in a) {a[$0]++; c++}
     END {for(i in a) print i,"was found",a[i]+0",times
          print NR-c,"lines did not match" }' file1 file2 file3