如何按初始列(带标题)拆分 CSV 文件?

l0b*_*0b0 3 shell text-processing

这是另外两个问题的组合(如何按每行前缀拆分文件以及如何根据列拆分文件,包括标题)。我想从以下内容开始input.csv

id,first,second,third
1,a,b,c
333,b,b,b
1,d,e,f
2,d,e,f
1,c,d,e
333,a,a,a
[more lines in the same format]
Run Code Online (Sandbox Code Playgroud)

到此内容1.csv

id,first,second,third
1,a,b,c
1,d,e,f
1,c,d,e
Run Code Online (Sandbox Code Playgroud)

,此内容在2.csv

id,first,second,third
2,d,e,f
Run Code Online (Sandbox Code Playgroud)

,以及此内容333.csv

id,first,second,third
333,b,b,b
333,a,a,a
Run Code Online (Sandbox Code Playgroud)

, 那是:

  1. 将所有 ID 为N的行放入N.csv.
  2. 保持原始行的顺序
  3. 在所有输出文件中包含来自原始文件的标题

这也必须非常快,所以while read循环不会切断它。

l0b*_*0b0 8

这个 GNU awk 命令可以解决问题:

awk -F ',' 'NR==1{h=$0; next};!seen[$1]++{f=$1".csv"; print h > f};{f=$1".csv"; print >> f; close(f)}' input.csv
Run Code Online (Sandbox Code Playgroud)

警告:如果第一个字段中有转义的逗号,这将不起作用。其他领域的逗号应​​该可以正常工作。

解释:

  • -F ','(字段分隔符)确保$1等引用 CSV 列而不是空格分隔值。
  • NR==1{h=$0; next}NR==1通过将完整的标题行存储在变量h( h=$0) 中并跳过行 ( next) 来特别对待第一行 ( )。
  • !seen[$1]++{f=$1".csv"; print h > f}通过将后跟存储到文件名变量并将标头保存到该文件 ( )来处理任何$1特殊 ( !seen[$1])的第一次出现。$1.csvfprint h > f
  • {f=$1".csv"; print >> f; close(f)}将当前行添加到文件 ( print >> f) 并关闭文件描述符 ( close(f)) 以避免在处理完具有特定 ID 的所有行后保留它。

奖励:如果您$1用另一个字段替换它应该按照您的预期执行:在该列中为每个唯一值创建一个文件,其中包含给定列中包含该值的行。