如何将CODE/LINE/SYMBOL多行数据按指定列格式合并输出?
数据转换解决方案
问题说明
我有如下格式的多行数据:
CODE> AA LINE1>ABCD LINE2>AJDS LINE3>AJDO SYMBOL1>Q1 SYMBOL2>Q2 SYMBOL3>Q3 SYMBOL4>Q4 CODE> BB LINE1>HFIN LINE2>HPAD LINE3>HIDF LINE4>HINA SYMBOL1>SA SYMBOL2>SS CODE> CC
需要将其转换为表格形式:同一CODE值重复显示,LINE和SYMBOL按序号匹配,数量不匹配时对应位置留空,预期结果如下:
| CODE | LINE | SYMBOL |
|---|---|---|
| AA | ABCD | Q1 |
| AA | AJDS | Q2 |
| AA | AJDO | Q3 |
| AA | Q4 | |
| BB | HFIN | SA |
| BB | HPAD | SS |
| BB | HIDF | |
| BB | HINA |
我尝试用以下命令:
grep -e CODE -e LINE -e SYMBOL test.txt |awk'NR%4{printf"%s",$1,$2,$3;}4'
但没得到预期结果,求正确解法。
正确解决方案
可以用awk脚本完成这个处理逻辑,无需提前grep筛选,脚本会按CODE分组收集数据,再按最大条目数循环输出:
BEGIN { # 输出markdown表头及对齐格式 printf "| CODE | LINE | SYMBOL |\n" printf "| :--- | :---: | -----: |\n" } # 匹配CODE行,先输出上一组数据(如果存在),再重置当前组 /^CODE>/ { if (code != "") { # 取当前组LINE和SYMBOL的最大条目数 max = (lines_cnt > symbols_cnt) ? lines_cnt : symbols_cnt # 循环输出每一行,空值自动留空 for (i=1; i<=max; i++) { printf "| %-3s | %-5s | %-6s |\n", code, lines[i], symbols[i] } # 清空当前组数据 delete lines delete symbols lines_cnt = 0 symbols_cnt = 0 } # 提取当前CODE值 split($0, arr, ">") code = arr[2] next } # 匹配LINE行,按序号存入数组 /^LINE[0-9]+>/ { split($0, arr, ">") num = substr(arr[1], 5) # 提取LINE后的序号 lines[num] = arr[2] if (num > lines_cnt) lines_cnt = num next } # 匹配SYMBOL行,按序号存入数组 /^SYMBOL[0-9]+>/ { split($0, arr, ">") num = substr(arr[1], 7) # 提取SYMBOL后的序号 symbols[num] = arr[2] if (num > symbols_cnt) symbols_cnt = num next } # 处理文件末尾的最后一组数据 END { if (code != "") { max = (lines_cnt > symbols_cnt) ? lines_cnt : symbols_cnt for (i=1; i<=max; i++) { printf "| %-3s | %-5s | %-6s |\n", code, lines[i], symbols[i] } } }
使用步骤
- 将上述脚本保存为
convert.awk文件 - 在终端执行命令:
awk -f convert.awk test.txt
这个脚本会自动处理每个CODE分组,按序号匹配LINE和SYMBOL条目,数量不匹配的位置自动留空,完全符合需求。
内容的提问来源于stack exchange,提问作者Sandeep Kumar
相关产品推荐
相关产品推荐

