从巨大的文件中 Grep 大量的模式

从巨大的文件中 Grep 大量的模式

我有一个每天增长约 200,000 行的文件,它全部由三行块组成,如下所示:

1358726575123       # key
    Joseph Muller   # name
    carpenter       # job
9973834728345
    Andres Smith
    student
7836472098652
    Mariah Anthony
    dentist

现在,我有另一个文件,我从中提取了大约 10,000 个关键模式,例如1358726575123.然后我for用这些模式运行一个循环,并且必须根据第一个文件检查它们。如果文件不包含此类模式,我会将模式保存在第三个文件中以供进一步处理:

for number in $(grep -o '[0-9]\{12\}' file2); do  # finds about 10.000 keys
     if ! grep -q ^$number$ file1; then           # file1 is a huge file
         printf "$number\n" >>file3               # we'll process file3 later
     fi
done

示例代码 grep 一个大文件 10,000 次,我运行这个循环大约一分钟一次,一整天

由于大文件不断增长,我该怎么做才能使这一切更快并节省一些 CPU?我想知道是否按文件的键对文件进行排序(如果是,如何?)或使用数据库而不是纯文本会有所帮助......

答案1

当然,问题在于您对大文件运行 grep 10,000 次。您应该只读取这两个文件一次。如果您不想使用脚本语言,可以这样做:

  1. 从文件 1 中提取所有数字并对其进行排序
  2. 从文件 2 中提取所有数字并对它们进行排序
  3. 在排序列表上运行comm以获取仅在第二个列表中的内容

像这样的东西:

$ grep -o '^[0-9]\{12\}$' file1 | sort -u -o file1.sorted
$ grep -o  '[0-9]\{12\}'  file2 | sort -u -o file2.sorted
$ comm -13 file1.sorted file2.sorted > file3

man comm

如果您可以每天截断大文件(如日志文件),您可以保留排序数字的缓存,并且不需要每次都解析它。

答案2

此答案基于awk发布的答案波东..对于相同的情况,它的速度是该方法(在我的系统上)
的两倍comm600万行在主文件中和1万键...(现已更新为使用 FNR、NR)

尽管awk比您当前的系统更快,并且会给您和您的计算机一些喘息空间,但请注意,当数据处理像您所描述的那样激烈时,通过切换到专用数据库您将获得最佳的整体结果;例如。 SQLite、MySQL...


awk '{ if (/^[^0-9]/) { next }              # Skip lines which do not hold key values
       if (FNR==NR) { main[$0]=1 }          # Process keys from file "mainfile"
       else if (main[$0]==0) { keys[$0]=1 } # Process keys from file "keys"
     } END { for(key in keys) print key }' \
       "mainfile" "keys" >"keys.not-in-main"

# For 6 million lines in "mainfile" and 10 thousand keys in "keys"

# The awk  method
# time:
#   real    0m14.495s
#   user    0m14.457s
#   sys     0m0.044s

# The comm  method
# time:
#   real    0m27.976s
#   user    0m28.046s
#   sys     0m0.104s

答案3

是的,一定要使用数据库。它们正是为此类任务而设计的。

答案4

有了这么多数据,您确实应该切换到数据库。同时,要获得接近不错的性能,您必须做的一件事是不要file1单独搜索每个键。运行一次grep以一次性提取所有非排除键。由于这grep也会返回不包含键的行,因此将其过滤掉。

grep -o '[0-9]\{12\}' file2 |
grep -Fxv -f - file1 |
grep -vx '[0-9]\{12\}' >file3

-Fx字面意思是搜索整行。-f -意思是从标准输入读取模式列表。)

相关内容