过滤包含固定数量的模式出现次数的行

过滤包含固定数量的模式出现次数的行

假设有文件

foo bar cat dog
foo foo cat bar
bar foo foo foo

我们如何 grep 查找出现一定次数的行,例如,foo如果次数是1只应打印示例文件中的第一行?

答案1

$ grep 'foo' file | grep -v 'foo.*foo'

首先挑出包含 的所有行foo,然后删除所有带有 的行,foo然后删除foo该行中的另一行。

如果所有行至少包含一个foo(如您的示例中所示),您可以跳过第一个grep.

对于“我如何grep准确地字符串出现?”: grep对于至少包含以下内容的行匹配,然后删除行N+1匹配(或更多)。

答案2

对于一般情况 - 仅打印精确的行您可以使用awk'sgsub()来返回编号。进行的替换并打印该行(如果没有)。符合要求,例如打印恰好出现 3 次的行:

 awk '{l=$0;t=gsub(/foo/,"",l)}t==3' infile

另一种方式sed

sed 's/foo/&/3   
t x
: k
d
: x
s/foo/&/4
t k' infile

这会尝试将第三次出现的内容替换为自身,如果失败,则删除该行d;如果成功,它会分支到: x尝试用自身替换第四次出现的地方 - 如果成功(这意味着有超过 3 次出现),它会分支到: k(以便该行也被删除),否则它不执行任何操作(除了自动打印该行之外)。 ..)


对于示例中的特定情况(仅出现一次的行),您还可以使用

sed '/foo/!d;/foo.*foo/d' infile

或类似的东西:

pcregrep '^(?:(?!foo).)*foo((?:(?!foo).)*)$' infile

答案3

使用grep -c来计数:

while read line; do [[ $(echo $line | sed 's/ /\n/g' | grep -c foo) == 2 ]] && echo "$line"; done < file.txt

答案4

另一种选择可能是使用perl,例如将匹配项推送到列表上下文中,然后在标量上下文中测试它:

perl -ne 'my $count = () = $_ =~ /foo/g; print if $count == 1' file

或没有显式标量变量

perl -ne 'print if ( () = $_ =~ /foo/g ) == 1' file

这种方法很容易推广到返回具有任何其他所需数量的匹配项的行。

参见示例Perl 是否有计算字符串中匹配项数量的快捷方式?

相关内容