如何用Linux命令行工具合并CSV列,使每行固定为14列?
用awk轻松搞定CSV列合并,固定为14列
嘿,你的需求用awk来处理最顺手了——它能灵活应对每行14到20列的差异,一次性完成列合并和格式调整,比cut+paste的组合方案高效太多。下面分两种常见场景给你具体方案:
场景1:CSV里没有带逗号的单元格(简单情况)
如果你的CSV所有逗号都是列分隔符,没有单元格用引号包裹并包含逗号(比如"Smith, Jane"这种情况),直接用这个简洁的awk脚本就行:
BEGIN { FS = ","; OFS = "," } { # 算清楚需要合并多少次:原列数减14,每次合并减少1列 merge_times = NF - 14 for (i=1; i<=merge_times; i++) { # 把第10列和第11列合并,后面的列依次往前挪一位 $10 = $10 "," $11 for (j=11; j<NF; j++) { $j = $(j+1) } NF-- # 列数减1,确保下次合并的位置正确 } print # 输出调整后的14列 }
把这段代码存成merge_csv_cols.awk,然后运行:
awk -f merge_csv_cols.awk your_data.csv
简单解释下:
- 开头的
BEGIN块把输入输出的分隔符都设为逗号,保证CSV格式不乱。 - 对每一行,先算出需要合并的次数:比如原行有20列,那就要合并6次(20-14=6),每次都把当前的第10和11列合并,然后后面的列往前移,直到总列数变成14。
- 最后直接输出调整好的行就行。
场景2:CSV存在带逗号的引号包裹单元格(复杂情况)
如果你的CSV里有单元格用双引号包着,而且里面还有逗号(比如用户姓名列"Doe, John"),上面的简单脚本会把引号里的逗号当成列分隔符,直接用就会出错。这时候得用awk的FPAT功能来正确识别带引号的单元格:
BEGIN { # 定义单元格的格式:要么是不含逗号的字符串,要么是双引号包裹的字符串(内部可以有逗号) FPAT = "([^,]+)|(\"[^\"]+\")" OFS = "," } { merge_times = NF - 14 for (i=1; i<=merge_times; i++) { # 合并时处理引号,避免出现"abc","def"变成"abc","def"这种冗余格式 if ($10 ~ /^"/ && $11 ~ /"$/) { # 去掉中间重复的引号,合并成"abc,def" $10 = substr($10, 1, length($10)-1) "," substr($11, 2) } else { $10 = $10 "," $11 } # 前移后面的列,减少列数 for (j=11; j<NF; j++) { $j = $(j+1) } NF-- } # 输出前检查:如果单元格含逗号但没引号,自动加上引号,保证CSV格式合法 for (k=1; k<=NF; k++) { if ($k ~ /,/ && $k !~ /^"/) { $k = "\"" $k "\"" } } print }
运行方式和之前一样:
awk -f merge_csv_cols.awk your_data.csv
这个脚本的贴心之处:
FPAT能准确识别带引号的单元格,不会把内部的逗号当成列分隔符。- 合并带引号的单元格时,会自动处理重复的引号,保证合并后的单元格格式正确。
- 输出前还会检查所有单元格,如果有含逗号但没引号的,自动补上引号,避免后续处理CSV时出错。
备选:用cut+paste组合(仅适合简单CSV)
如果你更习惯用基础的shell工具,也可以用cut和paste来实现,但这个方法只适合没有引号内逗号的情况,而且需要写个bash循环处理每行的列数差异,不如awk灵活:
while IFS=, read -ra cols; do col_count=${#cols[@]} if (( col_count <= 14 )); then echo "${cols[*]}" | tr ' ' ',' continue fi # 提取前9列 front_part="${cols[@]:0:9}" # 合并第10列到倒数第5列(因为要保留最后4列) merged_part="${cols[@]:9:$((col_count - 13))}" merged_part=$(echo "$merged_part" | tr ' ' ',') # 提取最后4列 back_part="${cols[@]:$((col_count - 4)):4}" # 拼接输出 echo "$front_part,$merged_part,$back_part" | tr ' ' ',' done < your_data.csv
不过说实话,这个方案写起来麻烦,处理边缘情况容易出错,还是更推荐用awk的方案。
内容的提问来源于stack exchange,提问作者kainaw
相关产品推荐
相关产品推荐

