我有一百个CSV文件,每个文件有200k行,压缩成gzip。
具有相同结构的所有文件。第 15 列和第 18 列包含公司 ID 和操作。
两列在一行中都是唯一的。我想为每个 copanyID.action 创建一个文件。现在我运行以下命令:
zcat * | grep 'companyID.*action' | gzip > companyID.action.gz
我通过管道传输所有内容以避免磁盘 IO。
问题是我们有数百家公司和大约20项行动。在每个公司 ID X 操作上运行此命令,每次都会扫描整个数据。
我正在寻找一种解决方案,可以扫描一次输入文件并将一行写入正确的文件,如果该文件不存在,请创建一个。
我更喜欢 bash 或 Golang 代码,但速度很重要,所以每个解决方案都值得检查
用awk
来做。
scat * | awk '{ print | "gzip > " $15 "." $18 ".gzip" }'
这应该可以做到:
zcat * |
awk -F, '{cmd="gzip >> ""$15"."$18".zip""} cmd!=prev{close(prev)} {print | cmd; prev=cmd}'
使用 GNU awk,您不需要cmd!=prev{close(prev)}
部分,如果您这样做:
zcat * |
sort -t, -k15,15 -k18,18 |
awk -F, '{cmd="gzip > ""$15"."$18".zip""} cmd!=prev{close(prev)} {print | cmd; prev=cmd}'
它可能会运行得更快,因为它只会在 awk 命令中打开/关闭每个输出管道一次,只是取决于sort
需要多长时间。
scat
是做什么的。我改用了zcat
。我按相关列对所有文件的所有行进行排序,然后在 Perl 中处理输出,当相关列中的值更改时更改输出文件:
zcat *.csv.gz
| sort -t, -k15,15 -k18,18
| perl -laF, -ne '
if ($company ne $F[14] || $action ne $F[17]) {
($company, $action) = @F[14, 17];
open FH, ">", "$company.$action.csv"
}
print FH $_'
gzip *.*.csv