Unix下拆分CSV文件:避免首列相同行被分割
如何按首列分组拆分大CSV文件(避免同组行拆分到不同文件)
你的需求很明确:处理已排序的超大CSV(7GB、1亿行),拆分时要保证首列值相同的行始终在同一个文件里,不能像split那样硬按行数/大小切割。确实,awk是解决这类问题的最佳工具,它能高效处理大文件,同时灵活控制分组逻辑。
核心思路
因为你的CSV已经按首列排序,所以相同首列的行是连续的。我们只需要跟踪当前输出文件的行数/大小,当新增行超过预设阈值时,检查当前行的首列是否和上一行一致:
- 如果不一致:切换到新文件
- 如果一致:继续写入当前文件,避免拆分同组数据
方案1:按行数拆分(约100K行/文件)
下面的awk脚本会把文件拆分成最多100K行/文件,但会确保同首列的行不被拆分:
BEGIN { # 设置目标行数,可根据需求调整 target_lines = 100000 file_num = 0 current_lines = 0 prev_key = "" # 打印进度到stderr,避免和输出文件内容混淆 printf "Creating output file x%05d\n", file_num > "/dev/stderr" out_file = sprintf("x%05d", file_num) } # 按逗号分隔提取首列 { current_key = $1 # 检查是否需要切换文件:当前行数+1超过阈值,且当前行首列和上一行不同 if (current_lines + 1 > target_lines && current_key != prev_key) { file_num++ current_lines = 0 printf "Creating output file x%05d\n", file_num > "/dev/stderr" out_file = sprintf("x%05d", file_num) } # 写入当前行到输出文件 print >> out_file current_lines++ prev_key = current_key } END { printf "拆分完成,共创建 %d 个文件\n", file_num + 1 > "/dev/stderr" }
使用方法
- 把上面的脚本保存为
split_csv_by_lines.awk - 运行命令:
awk -F ',' -f split_csv_by_lines.awk your_large_file.csv
方案2:按文件大小拆分(约6MB/文件)
如果更倾向于按文件大小拆分,下面的脚本会把文件拆分成最多6MB/文件,同样保证同首列行不拆分:
BEGIN { # 设置目标大小(6MB,可根据需求调整) target_size = 6 * 1024 * 1024 file_num = 0 current_size = 0 prev_key = "" printf "Creating output file x%05d\n", file_num > "/dev/stderr" out_file = sprintf("x%05d", file_num) } { current_key = $1 # 计算当前行的大小(包含换行符) line_size = length($0) + 1 # 检查是否需要切换文件:当前大小+当前行大小超过阈值,且当前行首列和上一行不同 if (current_size + line_size > target_size && current_key != prev_key) { file_num++ current_size = 0 printf "Creating output file x%05d\n", file_num > "/dev/stderr" out_file = sprintf("x%05d", file_num) } print >> out_file current_size += line_size prev_key = current_key } END { printf "拆分完成,共创建 %d 个文件\n", file_num + 1 > "/dev/stderr" }
使用方法
- 保存为
split_csv_by_size.awk - 运行命令:
awk -F ',' -f split_csv_by_size.awk your_large_file.csv
关键注意事项
- 必须保证CSV已排序:脚本依赖首列相同的行连续排列,否则会出现同首列行被拆分的情况。你已经说明文件是排序好的,所以没问题。
- 高效处理大文件:awk是原生编译的工具,处理7GB级别的文件速度很快,不会像Python等脚本语言那样出现内存瓶颈。
- 文件名格式:输出文件名是
x00000、x00001...和你预期的格式完全一致。 - 进度可见:脚本会把创建文件的进度打印到标准错误流(stderr),你可以实时看到拆分进度,不会干扰输出文件内容。
测试验证
用你提供的示例数据测试(把target_lines改成2),脚本会生成3个文件,完全符合你的预期结果:
- x00000:包含3行AABB1122的记录
- x00001:包含2行CCDD4444的记录
- x00002:包含CCEE4444和DDFF9900的所有记录
内容的提问来源于stack exchange,提问作者17th Lvl Botanist
相关产品推荐
相关产品推荐

