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 是否没有解决方法。
是的,你可以这样做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)sed
和wc
:
$ 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
。