动态BASH脚本实现TSV文件列拆分归一化问题排查与优化
动态TSV列拆分脚本问题排查与最优实现
需求说明
- 编写BASH脚本,从命令行接收以下参数:分隔符、需拆分的列号(支持多个,逗号分隔)、输入TSV文件路径、输出TSV文件路径
- 核心功能:将指定列中用分隔符分隔的内容拆分为多行,其余列内容对应复制到每一行
输入输出示例
输入TSV示例
COL1 COL2 COL3 COL4 YES NOT NAME,EX LOL,OK Y N NICE,ED LOUD,ONE YE NO NEED,ER LONE,TWO
期望输出TSV示例
COL1 COL2 COL3 COL4 YES NOT NAME LOL YES NOT EX OK Y N NICE LOUD Y N ED ONE YE NO NEED LONE YE NO ER TWO
现有脚本异常输出
COL1 COL2 COL4 COL4 YES NOT LOL LOL,OK YES NOT OK LOL,OK Y N LOUD LOUD,ONE Y N ONE LOUD,ONE YE NO LONE LONE,TWO YE NO TWO LONE,TWO
问题排查
从异常输出可明确两个核心问题:
- 列结构错乱:原COL3列丢失,COL4列重复输出,说明脚本处理列索引时逻辑错误,未正确保留原有列的位置和数量
- 拆分逻辑缺失:仅单独拆分了COL4列,未同步处理COL3列,且错误保留了原列的未拆分内容,完全不符合多列同步拆分的需求
最优实现方案
使用awk实现是最高效的选择,其原生支持文本列处理,可轻松适配多列同步拆分场景。以下是完整脚本:
#!/bin/bash # 参数合法性检查 if [ $# -ne 4 ]; then echo "用法: $0 <分隔符> <需拆分的列号(逗号分隔)> <输入TSV> <输出TSV>" echo "示例: $0 ',' '3,4' input.tsv output.tsv" exit 1 fi DELIM="$1" SPLIT_COLS="$2" INPUT_FILE="$3" OUTPUT_FILE="$4" # 将逗号分隔的列号转为数组 IFS=',' read -ra TARGET_COLS <<< "$SPLIT_COLS" # awk核心处理逻辑 awk -v delim="$DELIM" -v target_cols="$SPLIT_COLS" ' BEGIN { # 初始化目标列索引数组(awk列索引从1开始) split(target_cols, cols, ",") col_count = length(cols) for (i=1; i<=col_count; i++) { split_col[i] = cols[i] + 0 } FS = "\t" OFS = "\t" } # 表头直接输出 NR == 1 { print $0 next } { # 先拆分所有目标列,记录最长的拆分长度(处理列间拆分后元素数不一致的情况) max_rows = 0 for (i=1; i<=col_count; i++) { c = split_col[i] split($c, cell_arr[c], delim) if (length(cell_arr[c]) > max_rows) { max_rows = length(cell_arr[c]) } } # 生成多行输出 for (row=1; row<=max_rows; row++) { output_line = "" for (col=1; col<=NF; col++) { # 判断当前列是否为目标拆分列 is_target = 0 for (i=1; i<=col_count; i++) { if (col == split_col[i]) { is_target = 1 break } } # 非目标列直接复制原内容,目标列取对应行的元素(不足则补空) if (is_target) { content = cell_arr[col][row] ? cell_arr[col][row] : "" } else { content = $col } # 拼接输出行,最后一列不加分隔符 output_line = output_line (col == 1 ? "" : OFS) content } print output_line } } ' "$INPUT_FILE" > "$OUTPUT_FILE"
脚本说明
- 参数校验:先检查输入参数数量,避免非法调用
- 表头处理:第一行直接输出,不做拆分操作
- 多列同步拆分:
- 先拆分所有指定列,记录最长的拆分结果长度,确保列间元素数不一致时,短列自动补空
- 按最长长度循环生成每行内容,非目标列直接复制原数据,目标列取对应索引的拆分元素
- TSV格式兼容:严格使用
\t作为输入输出分隔符,保证TSV格式的正确性
使用示例
给脚本赋予执行权限后,按以下方式调用:
chmod +x split_tsv_cols.sh ./split_tsv_cols.sh ',' '3,4' input.tsv output.tsv
运行后即可得到符合预期的输出结果。
内容的提问来源于stack exchange,提问作者sasa.asa
相关产品推荐
相关产品推荐

