解析大量文件的高效方法

Efficient method to parse large number of files

我的传入数据将在 130GB - 300GB 范围内,其中包含 1000 个(可能是数百万个)大小为 2KB - 1MB 的小型 .txt 文件,位于单个文件夹中。我想有效地解析它们。

我正在查看以下选项(引用自 - 21209029]:

  1. 使用printf + xargs(后面是egrep & awk文本处理)

    printf '%s[=10=]' *.txt | xargs -0 cat | egrep -i -v 'pattern1|...|pattern8' | awk '{gsub(/"\t",",")}1' > all_in_1.out
    
  2. 使用find + cat(后面是egrep & awk文本处理)

    find . -name \*.txt -exec cat {} > all_in_1.tmp \;
    cat all_in_1.tmp | egrep -i -v 'pattern1|...|pattern8' | awk '{gsub(/"\t",",")}1' > all_in_1.out
    
  3. 使用for循环

    for file in *.txt
    do
      cat "$file" | egrep -i -v 'pattern1|...|pattern8' | awk '{gsub(/"\t",",")}1' >> all_in_1.out
    done
    

以上哪一项效率最高?有更好的方法吗?

或者根本不推荐使用 shell 命令来处理如此大量的数据(我确实更喜欢 shell 方式)?

服务器有 RHEL 6.5 OS,内存为 32 GB,16 核 (@2.2GHz)。

方法 1 和 3 在 shell 命令行上展开文件列表。这不适用于大量文件。如果文件分布在许多目录中(可能有数百万个文件),方法 1 和方法 3 也不起作用。

方法 2 复制所有数据,因此效率也很低。

您应该使用 find 并将文件名直接传递给 egrep。使用 -h 选项来抑制带有文件名的前缀:

find . -name \*.txt -print0 \
 | xargs -0 egrep -i -v -h 'pattern1|...|pattern8' \
 | awk '{gsub(/"\t",",")}1' > all_in_1.out

xargs 将自动按顺序启动多个 egrep 进程,以避免在单次调用中超过命令行限制。

根据文件内容,完全避免 egrep 过程,直接在 awk:

中进行过滤也可能更有效
find . -name \*.txt -print0 \
 | xargs -0 awk 'BEGIN { IGNORECASE = 1 } ! /pattern1|...|pattern8/ {gsub(/"\t",",")}1' > all_in_1.out

BEGIN { IGNORECASE = 1 }对应egrep-i选项,!-v的匹配意​​义相反。 IGNORECASE 似乎是 GNU 扩展。