I have a directory with quite some files. I have n search patterns and would like to list all files that match m of those.
Example: From the files below, list the ones that contain at least two of str1, str2, str3 and str4.
$ ls -l dir/
total 16
-rw-r--r--. 1 me me 10 Jun 22 14:22 a
-rw-r--r--. 1 me me 5 Jun 22 14:22 b
-rw-r--r--. 1 me me 10 Jun 22 14:22 c
-rw-r--r--. 1 me me 9 Jun 22 14:22 d
-rw-r--r--. 1 me me 10 Jun 22 14:22 e
$ cat dir/a
str1
str2
$ cat dir/b
str2
$ cat dir/c
str2
str3
$ cat dir/d
str
str4
$ cat dir/e
str2
str4
I managed to achieve this with a rather ugly for loop on find results that spawns n grep processes for each file, which obviously is super inefficient and would take ages on directories with a lot of files:
for f in $(find dir/ -type f); do
c=0
grep -qs 'str1' $f && let c++
grep -qs 'str2' $f && let c++
grep -qs 'str3' $f && let c++
grep -qs 'str4' $f && let c++
[[ $c -ge 2 ]] && echo $f
done
I am quite sure I could achieve this in a far better performing way, but I am not sure how to tackle it. From what I understand from the man page (i.e. on -e and -m) this is not possible with grep alone.
What would be the right tool to use? Is this possible with awk?
Bonus: By using find I can define the files to search more precisely (i.e. -prune certain sub directories or only search files with -iname '*.txt'), which I would like to do with other solutions, too.
UPDATE
Some statistics about the performance of different implementations below.
find + awk
(Script from this answer)
real 0m0,006s
user 0m0,002s
sys 0m0,004s
python
(I'm a python noob, please advise if this could be optimized):
import os
patterns = []
patterns = ["str1", "str2", "str3", "str4"]
for root, dirs, files in os.walk("dir"):
for file in files:
c = int(0)
filepath = os.path.join(root, file)
with open(filepath, 'r') as input:
for pattern in patterns:
for line in input:
if pattern in line:
c += 1
break
if ( c >= 2 ):
print(filepath)
real 0m0,025s
user 0m0,019s
sys 0m0,006s
c++
(Script from this answer)
real 0m0,002s
user 0m0,001s
sys 0m0,001s