AWK 问题:计数 "non-matches"

AWK issue : counting "non-matches"

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

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

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.

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

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, "was found on", count[name], "lines." }
   ' test.txt

我在 if 语句中遇到这样的错误:

awk: syntax error at source line 6
 context is
        >>>  if <<<  (found==0) { count["none"]++; }
awk: bailing out at source line 8

知道为什么这不起作用吗?

考虑到您要打印仅出现 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 and inside {} we have the 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 所以如果项目是空字符串,将打印零。

有几种方法可以实现您想要的效果。虽然 OP 提供的方法有效,但它并不真正灵活。我们假设您有一个字符串 str,其中包含您感兴趣的单词:

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