【发布时间】:2020-10-12 09:04:03
【问题描述】:
我有一个包含很多文件的目录。我有 n 搜索模式,并想列出与其中 m 匹配的所有文件。
示例:从下面的文件中,列出至少包含 两个 的 str1、str2、str3 和 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
我设法通过在find 结果上产生n grep 进程的相当丑陋的for 循环来实现这一点,这显然是超级低效的,并且在包含大量文件的目录上会花费很长时间:
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
我很确定我可以以更好的方式实现这一目标,但我不知道如何解决它。根据我从手册页(即-e 和-m)中了解到的信息,仅使用grep 是不可能的。
什么是合适的工具? awk 可以做到这一点吗?
奖励:通过使用find,我可以更精确地定义要搜索的文件(即-prune 某些子目录或仅搜索带有-iname '*.txt' 的文件),我也想使用其他解决方案。
更新
关于以下不同实现的性能的一些统计数据。
find + awk
(来自this答案的脚本)
real 0m0,006s
user 0m0,002s
sys 0m0,004s
python
(我是python noob,请告知是否可以优化):
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++
(来自this答案的脚本)
real 0m0,002s
user 0m0,001s
sys 0m0,001s
【问题讨论】:
-
您发布的计时结果是否是第三次运行计时以消除结果中的缓存影响?我假设脚本需要 0.002s 还是 0.006s 对你来说并不重要,因为它们都在视线范围内 - 如果你有更大的文件,性能很重要,你可以使用这些来测试时间吗?此外,您正在将具有硬编码
str1等的 C++ 程序与从文件中读取值的 awk 程序进行比较——这显然不是苹果对苹果的比较。
标签: regex bash search awk grep