title: recursively list files that contain m of n regex
body: <p>I have a directory with quite some files. I have <code>n</code> search patterns and would like to list all files that match <code>m</code> of those.</p>
  <p>Example: From the files below, list the ones that contain at least <em>two</em> of <code>str1</code>, <code>str2</code>, <code>str3</code> and <code>str4</code>.</p>
  <pre class="lang-sh prettyprint-override"><code>$ 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
  </code></pre>
  <p>I managed to achieve this with a rather ugly <code>for</code> loop on <code>find</code> results that spawns <code>n</code> <code>grep</code> processes for each file, which obviously is super inefficient and would take ages on directories with a lot of files:</p>
  <pre class="lang-sh prettyprint-override"><code>for f in $(find dir/ -type f); do
    c=0
    grep -qs 'str1' $f &amp;&amp; let c++
    grep -qs 'str2' $f &amp;&amp; let c++
    grep -qs 'str3' $f &amp;&amp; let c++
    grep -qs 'str4' $f &amp;&amp; let c++
    [[ $c -ge 2 ]] &amp;&amp; echo $f
  done
  </code></pre>
  <p>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 <code>-e</code> and <code>-m</code>) this is not possible with <code>grep</code> alone.</p>
  <p>What would be the right tool to use? Is this possible with <code>awk</code>?</p>
  <p>Bonus: By using <code>find</code> I can define the files to search more precisely (i.e. <code>-prune</code> certain sub directories or only search files with <code>-iname '*.txt'</code>), which I would like to do with other solutions, too.</p>
  <hr />
  <h1>UPDATE</h1>
  <p>Some statistics about the performance of different implementations below.</p>
  <hr />
  <h3><code>find</code> + <code>awk</code></h3>
  <p>(Script from <a href="https://stackoverflow.com/a/62516128/2656118">this</a> answer)</p>
  <pre><code>real    0m0,006s
  user    0m0,002s
  sys     0m0,004s
  </code></pre>
  <hr />
  <h3><code>python</code></h3>
  <p>(I'm a <code>python</code> noob, please advise if this could be optimized):</p>
  <pre class="lang-py prettyprint-override"><code>import os
  
  patterns = []
  patterns = [&quot;str1&quot;, &quot;str2&quot;, &quot;str3&quot;, &quot;str4&quot;]
  
  for root, dirs, files in os.walk(&quot;dir&quot;):
      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 &gt;= 2 ):
              print(filepath)
  </code></pre>
  <pre><code>real    0m0,025s
  user    0m0,019s
  sys     0m0,006s
  </code></pre>
  <hr />
  <h3><code>c++</code></h3>
  <p>(Script from <a href="https://stackoverflow.com/a/62519890/2656118">this</a> answer)</p>
  <pre><code>real    0m0,002s
  user    0m0,001s
  sys     0m0,001s
  </code></pre>