Suppose there is file

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

How do we grep for lines with a certain number of occurrences of foo e.g. if the number is 1 only the first line in the sample file should be printed ?

  • exactly 2 matches – Rahul Aug 15 '16 at 21:12
$ grep 'foo' file | grep -v 'foo.*foo'

First pick out all lines containing foo, then remove all lines with foo followed by another foo somewhere on the line.

If all lines contain at least one foo (as in your example), you may skip the first grep.

For a general solution to "How do I grep for exactly N occurrences of a string?": grep for lines with at least N matches, then remove lines with N+1 matches (or more).

  • How does one print out all lines with three occurrences of foo with this method? – Alexander Aug 16 '16 at 8:02
  • 1
    @Alexander Grep for all lines containing at least three occurrences, then filter out the ones that contain four or more. In the general case: grep for at least N occurrences and remove N+1 occurrences or more. – Kusalananda Aug 16 '16 at 8:11

For the general case - print only lines with exactly N occurrences you could use awk's gsub() which returns the no. of substitutions made and print the line if that no. matches the requirement e.g. to print lines with exactly three occurrences:

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

Another way with sed:

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

This attempts to replace the 3rd occurrence with itself, if it fails the line is deleted; if successful it branches to : x where attempts to replace the 4th occurrence with itself - if successful (it means there are more than 3 occurrences) it branches to : k (so that line is also deleted) else it does nothing (besides auto-printing the line...)

For the particular case in your example (lines with only one occurrence) you could also use

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

or something like:

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

Using grep -c to count:

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

Another option might be to use perl, for example by pushing the matches into a list context and then testing it in a scalar context:

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

or without the explicit scalar variable

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

This way is easily generalized to return lines with any other desired number of matches.

See for example Is there a Perl shortcut to count the number of matches in a string?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.