我有一个大文本文件,我希望通过排除具有与特定字符匹配的列数的行来过滤。我之前删除了从2开始的所有列都包含0或a的行。像这样:
awk '{
for (i=2; i<=NF; i++)
if ($i!~/^(\.|0)/) {
print
break
}
}'
但是现在我想要它以便打印具有此值的特定列数少的行(&#34;。&#34;)。
例如数据:
A B C D E
0 1 . 0 0
1 ./. 0 1 1
1 1 0 0 0
0 0 . . 0
. ./. . . .
且匹配值为2我希望排除底部的两行,以便输出为:
A B C D E
0 1 . 0 0
1 ./. 0 1 1
1 1 0 0 0
有什么想法吗?
答案 0 :(得分:3)
使用awk:
$ awk '{c=0;for(i=1;i<NF;i++) c += ($i == ".")}c<2' file
A B C D E
0 1 . 0 0
1 ./. 0 1 1
1 1 0 0 0
基本上,如果列等于句点(.
),它会迭代每一列并向计数器添加一个。
如果列数少于两列,则c<2
部分仅打印该行。
使用sed可以使用:
$ sed -r 'h;s/[^. ]+//g;s/\.\. *//g;/\. \./d;x' file
A B C D E
0 1 . 0 0
1 ./. 0 1 1
1 1 0 0 0
-r
启用扩展正则表达式(-E
on * BSD)。
基本上,模式空间的副本存储在h
旧缓冲区中,然后删除除空格和句点之外的所有空格。
现在,如果模式空间包含两个单独的句点,则可以删除它,如果模式空间不能通过保持缓冲区更改为x
。
答案 1 :(得分:2)
$ awk '{delete a; for(i=1;i<=NF;i++) a[$i]++; if(a["."]>=2) next} 1' foo
A B C D E
0 1 . 0 0
1 ./. 0 1 1
1 1 0 0 0
它会迭代记录中的所有字段(for
),计算字段值和if
2个或更多.
,从而限制打印(next
)。如果您只想从字段3开始计算期间,请在i
:for
中更改for(i=3; ...)
的起始值。
答案 2 :(得分:1)
$ cat ip.txt
A B C D E
0 1 . 0 0
1 ./. 0 1 1
1 1 0 0 0
0 0 . . 0
. ./. . . .
$ perl -ne '(@c)=/\.\/\.|\./g; print if $#c < 1' ip.txt
A B C D E
0 1 . 0 0
1 ./. 0 1 1
1 1 0 0 0
(@c)=/\.\/\.|\./g
数组./.
或.
与当前行匹配$#c
表示最后一个元素的索引,即(数组的大小 - 1)./.
或.
等3个元素的行,请使用$#c < 2
答案 3 :(得分:1)
与@ spasic的答案类似,但更容易(对我而言)阅读!
perl -ane 'print if (grep { /^\.$/} @F) < 2' file
A B C D E
0 1 . 0 0
1 ./. 0 1 1
1 1 0 0 0
-a
将空格分隔的字段分隔为一个名为@F
的数组。然后我在数组@F
中查找仅包含句点的元素 - 即以句点开头并在句点之后立即结束的元素。这会计算每行中的单个句点,如果该数字小于2,则打印该行。
答案 4 :(得分:-1)
也许这没关系。
awk '$0 !~/\. \./' file
A B C D E
0 1 . 0 0
1 ./. 0 1 1
1 1 0 0 0