根据列值拆分大文件并使用关闭命令时 AWK 非常慢

AWK very slow when splitting large file based on column value and using close command

我需要根据第一列中找到的 ID 将一个大日志文件拆分成多个较小的日志文件,这个解决方案在几个月内效果非常好并且非常快:

awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"}' ${nome}.all;

其中 $nome 是文件名和目录名。

速度非常快,直到日志文件达到几百万行+2GB 文本文件,然后才开始显示

"Too many open files"

解决方法确实很简单,加上关闭命令:

awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"; close(dir"/"dir"_"".log")}' ${nome}.all;

问题是,现在它非常慢,它需要很长时间才能完成几秒钟内完成的事情,我需要对此进行优化。

AWK 不是强制性的,我可以使用替代方法,只是不知道如何使用

未经测试,因为您没有提供任何样本 input/output 进行测试,但应该这样做:

sort -t';' -k1,1 "${nome}.all"  |
awk -v dir="$nome" -F\; '!=prev{close(out); out=dir"/"dir"_"".log"; prev=} {print > out}'

您的第一个脚本:

awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"}' ${nome}.all;

有 3 个问题:

  1. 它没有关闭文件名,因此超出了您看到的阈值。
  2. 它在输出重定向的右侧有一个未加括号的表达式,根据 POSIX.
  3. ,这是未定义的行为
  4. 它没有在文件名中引用 shell 变量 ${nome}

值得一提的是,gawk 能够处理 1 和 2 而不会失败,但是随着打开文件数量的增加它会变慢并且它必须在内部管理 opens/closes。

你的第二个脚本:

awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"; close(dir"/"dir"_"".log")}' ${nome}.all;

虽然现在关闭输出文件名,但问题 2 和 3 仍然存在,然后添加了 2 个新问题:

  1. 每个输入行打开和关闭输出文件一次,而不是仅在必须更改输出文件名时才打开和关闭一次。
  2. 它正在为写入的每一行每 $1 覆盖输出文件,而不是附加到它。

上面假设每个 $1 有多行输入,因此每个输出文件都有多行。否则,您在关闭输出文件时看到的减速就不会发生。

上面的sort可以重新排列每个$1的输入行的顺序。如果这是一个问题,请为“稳定排序”添加 -s(如果您有 GNU 排序)或让我们知道,因为使用 POSIX 工具很容易解决。