计算一个字符串在多列中出现 n 次的行数

KL_*_*KBK 4 awk text-processing

我有几百个文本文件,每个文件由五个制表符分隔的列组成。第一列包含一个索引,接下来的四列包含出现次数。现在我想计算包含 0 的 3 列(即下面示例中的 7 行)的行数。

1   0   0   0   9
2   0   9   0   0
3   10  0   0   0
4   0   10  4   0
5   0   0   0   10
6   0   0   0   10
7   0   0   0   10
8   0   10  0   0
9   5   0   5   0
Run Code Online (Sandbox Code Playgroud)

我可以将其编码为 R 中的循环,但是由于每个原始文件包含 60 多万行,我想知道 awk 或 sed 和 wc -l 是否没有解决方法。

ter*_*don 5

是的,你可以这样做awk

awk '{ 
       k=0; 
       for(i=2;i<=NF;i++){ 
         if($i == 0){
             k++
         }
       }
       if(k==3){
         tot++
       }
      }
      END{
          print tot
      }' file 
Run Code Online (Sandbox Code Playgroud)

还有(GNU)sedwc

$ sed -nE '/\b0\b.*\b0\b.*\b0\b/p' file | wc -l
7
Run Code Online (Sandbox Code Playgroud)

但是,就个人而言,我会用 perl 代替:

$ perl -ale '$tot++ if (grep{$_ == 0 } @F) == 3 }{ print $tot' file 
7
Run Code Online (Sandbox Code Playgroud)

或者,稍微不那么浓缩:

$ perl -ale 'if( (grep{$_ == 0 } @F) == 3 ){
                  $tot++ 
              }
              END{
                  print $tot
              }' file 
7
Run Code Online (Sandbox Code Playgroud)

同样的事情,对于你们中的高尔夫球手来说:

$ perl -ale '(grep{$_==0}@F)==3&&$t++}{print$t' file
7
Run Code Online (Sandbox Code Playgroud)

解释

  • -ale:-a使 perl 表现得像 awk。它将读取输入文件的每一行并将其在空白处拆分为数组@F。的-l增加了\n到的每个呼叫print由输入及排除尾随换行符和-e是应被应用到输入的每一行的脚本。
  • $tot++ if (grep{$_ == 0 } @F) == 3:$tot每次都有 3 个字段时加 1 0。由于第一个字段从 1 开始,我们知道它永远不会为 0,因此我们不需要排除它。
  • }{:这只是一种速记方式END{},提供了在处理文件后将执行的代码块。因此,}{ print $tot将打印具有正好三个值为 的字段的总行数0