Grepping 巨大的文件性能

mar*_*rio 5 grep bash large-files algorithms

我有超过 300K 行的 FILE_A 和超过 30M 行的 FILE_B。我创建了一个 bash 脚本,它将 FILE_A 中的每一行 grep 到 FILE_B 中,并将 grep 的结果写入一个新文件。

整个过程需要超过 5 个多小时。

我正在寻找有关您是否看到任何提高脚本性能的方法的建议。

我使用 grep -F -m 1 作为 grep 命令。FILE_A 看起来像这样:

123456789 
123455321
Run Code Online (Sandbox Code Playgroud)

和 FILE_B 是这样的:

123456789,123456789,730025400149993,
123455321,123455321,730025400126097,
Run Code Online (Sandbox Code Playgroud)

因此,使用 bash 我有一个 while 循环,它选择 FILE_A 中的下一行,并在 FILE_B 中将其遍历。当在 FILE_B 中找到模式时,我将其写入 result.txt。

while read -r line; do
   grep -F -m1 $line 30MFile
done < 300KFile
Run Code Online (Sandbox Code Playgroud)

非常感谢您的帮助。

Gil*_*il' 6

性能的关键是只读取一次大文件。

您可以通过将多个模式放在单独的行上来将多个模式传递给 grep。这通常是通过告诉 grep 从文件中读取模式来完成的:

grep -F -f 300KFile 30MFile
Run Code Online (Sandbox Code Playgroud)

这会按照大文件的顺序输出匹配项,并且只打印一次匹配多个模式的行。此外,这会查找行中任何位置的模式;例如,如果模式文件包含1234,则诸如123456,345678,2348962342和 之类的478912,1211138,1234行将匹配。

您可以通过预处理模式来限制精确的列匹配。例如,如果模式不包含任何特殊字符()?*+\|[]{}

<300KFile sed -e 's/^/(^|,)/' -e 's/$/($|,)/' |
grep -E -f - 30MFile
Run Code Online (Sandbox Code Playgroud)

如果仅保留每个模式的第一个匹配项很重要,则进行第一遍以仅提取上述相关行,然后在 awk 或 perl 中进行第二遍跟踪已经看到的模式。

<300KFile sed -e 's/^/(^|,)/' -e 's/$/($|,)/' |
grep -E -f - 30MFile |
perl -l -F, -ape '
    BEGIN {
        open P, "300KFile" or die;
        %patterns = map {chomp; $_=>1} <P>;
        close P;
    }
    foreach $c (@F) {
        if ($patterns{$c}) {
            print;
            delete $patterns{$c};
        }
    }
'
Run Code Online (Sandbox Code Playgroud)