How can I get lines where a specific word is repeated exactly N times?
Solution 1:
In perl
, replace this
with itself case-insensitively and count the number of replacements:
$ perl -ne 's/(this)/$1/ig == 3 && print' <<EOF
How to get This line that this word repeated 3 times in THIS line?
But not this line which is THIS word repeated 2 times.
And I will get This line with this here and This one
A test line with four this and This another THIS and last this
EOF
How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one
Using a count of matches instead:
perl -ne 'my $c = () = /this/ig; $c == 3 && print'
If you have GNU awk, a very simple way:
gawk -F'this' -v IGNORECASE=1 'NF == 4'
The number of fields will be one more than the number of separators.
Solution 2:
Assuming your source file is tmp.txt,
grep -iv '.*this.*this.*this.*this' tmp.txt | grep -i '.*this.*this.*this.*'
The left grep outputs all lines that do not have 4 or more case-insensitive occurrences of "this" in tmp.txt.
The result is piped to the right grep, which outputs all lines with 3 or more occurrences in the left grep result.
Update: Thanks to @Muru, here is the better version of this solution,
grep -Eiv '(.*this){4,}' tmp.txt | grep -Ei '(.*this){3}'
replace 4 with n+1 and 3 with n.
Solution 3:
In python, this would do the job:
#!/usr/bin/env python3
s = """How to get This line that this word repeated 3 times in THIS line?
But not this line which is THIS word repeated 2 times.
And I will get This line with this here and This one
A test line with four this and This another THIS and last this"""
for line in s.splitlines():
if line.lower().count("this") == 3:
print(line)
outputs:
How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one
Or to read in from a file, with the file as argument:
#!/usr/bin/env python3
import sys
file = sys.argv[1]
with open(file) as src:
lines = [line.strip() for line in src.readlines()]
for line in lines:
if line.lower().count("this") == 3:
print(line)
-
Paste the script into an empty file, save it as
find_3.py
, run it by the command:python3 /path/to/find_3.py <file_withlines>
Of course the word "this" can be replaced by any other word (or other string or line section), and the number of occurrences per line can be set to any other value in the line:
if line.lower().count("this") == 3:
Edit
If the file would be large (hundreds of thousands / millions of lines), the code below would be faster; it reads the file per line instead of loading the file at once:
#!/usr/bin/env python3
import sys
file = sys.argv[1]
with open(file) as src:
for line in src:
if line.lower().count("this") == 3:
print(line.strip())
Solution 4:
You can play a bit with awk
for this:
awk -F"this" 'BEGIN{IGNORECASE=1} NF==4' file
This returns:
How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one
Explanation
What we do is to define the field separator to
this
itself. This way, the line will have as many fields +1 as times the wordthis
appears.To make it case insensitive, we use
IGNORECASE = 1
. See reference: Case Sensitivity in Matching.Then, it is just a matter of saying
NF==4
to get all those lines havingthis
exactly three times. No more code is needed, since{print $0}
(that is, print the current line) is the default behaviour ofawk
when an expression evaluates toTrue
.
Solution 5:
Assuming the lines are stored in a file named FILE
:
while read line; do
if [ $(grep -oi "this" <<< "$line" | wc -w) = 3 ]; then
echo "$line";
fi
done <FILE