首页 > 解决方案 > 递归列出包含 m of n 正则表达式的文件

问题描述

我有一个包含很多文件的目录。我有n搜索模式,想列出所有匹配m的文件。

示例:从下面的文件中,列出至少包含、和中两个的文件。str1str2str3str4

$ 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

我设法通过一个相当丑陋的for循环来实现这一点,该循环为每个文件find生成n grep进程,这显然是超级低效的,并且在包含大量文件的目录上会花费很长时间:

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

我很确定我可以以更好的方式实现这一目标,但我不知道如何解决它。根据我从手册页(即 on-e-m)中了解到的情况,单独使用这是不可能的grep

什么是正确的工具?这可能awk吗?

奖励:通过使用find我可以更精确地定义要搜索的文件(即-prune某些子目录或仅搜索带有 的文件-iname '*.txt'),我也想用其他解决方案来做。


更新

下面是一些关于不同实现的性能的统计数据。


find+awk

(来自这个答案的脚本)

real    0m0,006s
user    0m0,002s
sys     0m0,004s

python

(我是python菜鸟,请告知是否可以优化):

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++

(来自这个答案的脚本)

real    0m0,002s
user    0m0,001s
sys     0m0,001s

标签: regexbashsearchawkgrep

解决方案


$ cat reg.txt
str1
str2
str3
str4
$ cat prog.awk
# reads regexps from the first input file
# parameterized by `m'
# requires gawk or mawk for `nextfile'
FNR == NR {
  reg[NR] = $0
  next
}
FNR == 1 {
  for (i in reg)
    tst[i]
  cnt = 0
}
{
  for (i in tst) {
    if ($0 ~ reg[i]) {
      if (++cnt == m) {
        print FILENAME
        nextfile
      }
      delete tst[i]
    }
  }
}
$ find dir -type f -exec awk -v m=2 -f prog.awk reg.txt {} +
dir/a
dir/c

推荐阅读