Bash排除列的比例包含匹配值

时间:2016-09-10 15:02:26

标签: bash awk

我有一个大文本文件,我希望通过排除具有与特定字符匹配的列数的行来过滤。我之前删除了从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

有什么想法吗?

5 个答案:

答案 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开始计算期间,请在ifor中更改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