Linux下以指定字段为唯一键实现垂直数据转水平过滤
问题描述
需要处理以<SUBBEGIN>和<SUBEND>包裹的订阅数据,提取指定字段并转换为指定的水平格式。
原始输入数据
<SUBBEGIN SUBSCRIBERIDENTIFIER=803838478; PAIDTYPE=0; SUBSCRIPTION=TOOMUCH&73337E0380B4B30F&1&AAA&BBB&CCC&1&1&FFFFFFFFFFFFFFFF&255&1&255&256&FFFFFFFFFFFFFFFF&0&0&128&1&255&255&FFFFFFFFFFFFFF&FFFFFFFFFFFFFF&0&0&0&1&0&0&1; SUBSCRIPTION=TASKS&E7CC601262AB3535&1&DDD&EEE&FFF&2&1&FFFFFFFFFFFFFFFF&255&0&255&256&FFFFFFFFFFFFFFFF&0&0&128&1&255&255&FFFFFFFFFFFFFF&FFFFFFFFFFFFFF&0&21&0&1&0&0&1; <SUBEND <SUBBEGIN SUBSCRIBERIDENTIFIER=705959905; PAIDTYPE=254; SUBSCRIPTION=REALLY&73337E0380B4B30F&1&GGG&HHH&LLL&1&1&FFFFFFFFFFFFFFFF&255&1&255&256&FFFFFFFFFFFFFFFF&0&0&128&1&255&255&FFFFFFFFFFFFFF&FFFFFFFFFFFFFF&0&0&0&1&0&0&1; SUBSCRIPTION=TIRED&E7CC601262AB3535&1&MMM&NNN&PPP&2&1&FFFFFFFFFFFFFFFF&255&0&255&256&FFFFFFFFFFFFFFFF&0&0&128&1&255&255&FFFFFFFFFFFFFF&FFFFFFFFFFFFFF&0&21&0&1&0&0&1; <SUBEND
预期表头
SUBSCRIBERIDENTIFIER,,,PAIDTYPE,,1,255,SERVICENAME,SUBSCRIBEDATETIME,VALIDFROMDATETIME,EXPIREDDATETIME,,,,,
字段提取规则
SUBSCRIBERIDENTIFIER:取自对应字段的数值(如803838478)PAIDTYPE:取自对应字段的数值(如0)SERVICENAME:取自SUBSCRIPTION字段的第一个&前的内容(如TOOMUCH)SUBSCRIBEDATETIME:SUBSCRIPTION字段的第4个分隔值(如AAA)VALIDFROMDATETIME:SUBSCRIPTION字段的第5个分隔值(如BBB)EXPIREDDATETIME:SUBSCRIPTION字段的第6个分隔值(如CCC)- 固定填充字段:
,,1,255,和末尾的,,,,,
尝试的脚本及错误输出
使用以下awk脚本:
awk -F"&" '/^<SUBBEGIN$/{a=1} a && /^[[:blank:]]+(SUBSCRIBERIDENTIFIER|PAIDTYPE|SUBSCRIPTION)/{l=l OFS $1} a && /^<SUBEND$/ {print l; a=l=""}' sample.txt
得到的错误输出:
SUBSCRIBERIDENTIFIER=803838478; PAIDTYPE=0; SUBSCRIPTION=TOOMUCH SUBSCRIPTION=TASKS SUBSCRIBERIDENTIFIER=705959905; PAIDTYPE=254; SUBSCRIPTION=REALLY SUBSCRIPTION=TIRED
解决方案
使用以下awk脚本可以实现需求:
awk ' /SUBBEGIN/ { in_block=1; next } /SUBEND/ { in_block=0; next } in_block { if ($0 ~ /SUBSCRIBERIDENTIFIER=/) { sub(/;$/, "", $0); split($0, arr, "="); sub_id = arr[2]; } else if ($0 ~ /PAIDTYPE=/) { sub(/;$/, "", $0); split($0, arr, "="); paid_type = arr[2]; } else if ($0 ~ /SUBSCRIPTION=/) { sub(/;$/, "", $0); split($0, arr, "="); sub_val = arr[2]; split(sub_val, sub_arr, "&"); printf "%s,,,%s,,1,255,%s,%s,%s,%s,,,,,\n", sub_id, paid_type, sub_arr[1], sub_arr[4], sub_arr[5], sub_arr[6]; } } ' sample.txt
脚本逻辑说明
- 标记数据块:遇到
SUBBEGIN时开启数据块标记in_block=1,遇到SUBEND时关闭标记。 - 提取固定字段:
- 处理
SUBSCRIBERIDENTIFIER行:去掉末尾分号,按=分割获取数值存入sub_id。 - 处理
PAIDTYPE行:同理获取数值存入paid_type。
- 处理
- 处理订阅字段:
- 去掉
SUBSCRIPTION行末尾分号,先按=分割出&分隔的内容。 - 再按
&分割该内容,提取第1、4、5、6个元素作为服务名和时间字段。
- 去掉
- 按预期格式拼接所有字段并打印,每个
SUBSCRIPTION行对应一行输出。
执行结果
运行脚本后将得到预期输出:
803838478,,,0,,1,255,TOOMUCH,AAA,BBB,CCC,,,,, 803838478,,,0,,1,255,TASKS,DDD,EEE,FFF,,,,, 705959905,,,254,,1,255,REALLY,GGG,HHH,LLL,,,,, 705959905,,,254,,1,255,TIRED,MMM,NNN,PPP,,,,,
内容的提问来源于stack exchange,提问作者rujak
相关产品推荐
相关产品推荐

