Filter lines that contain a fixed number of pattern occurrences
$ 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).
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
d
: x
s/foo/&/4
t k' infile
This attempts to replace the 3rd occurrence with itself, if it fails the line is d
eleted; 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