如何使用awk命令按指定位置字符分组求和并存储到变量?
问题描述
我手头有个固定格式的文本文件,需要按每行第67位的字符(要么是D要么是C),分别对第68到81位的数值求和,预期结果应该是D对应1600,C也对应1600。
文件内容是这样的:
10010001602171813800899901000000000101211000002007-05-130005316347D000000000000800 000000002007-05-18x?0000000000 10010001602171813800899901000000000201211000002007-05-130748402438C000000000000800 000000002007-05-18x?0000000000 10010001602171813800899901100000000101211000002007-05-130005316347D000000000000800 000000002007-05-18x?0000000000 10010001602171813800899901100000000201211000002007-05-130748402438C000000000000800 000000002007-05-18x?0000000000
我试了下面的命令:
grep "^1" file.txt | \ awk '{s[substr($0,67,68-67)]+=substr($0,68,83-68)} END { for (i in s) { print i, s[i] }}'
结果却不对,输出是:
C 1596678 D 1596678
而且我还需要把这两个求和结果分别存到独立的shell变量里,比如用A存D对应的和,B存C对应的和,该怎么弄呢?
解决方法
1. 先修正awk的截取错误
你之前的问题出在substr的参数用错了!awk里的substr语法是substr(字符串, 起始位置, 长度),不是起始到结束位置。
- 要取第67位的单个字符,应该用
substr($0, 67, 1)(从第67位开始,取1个字符) - 第68到81位一共是14个字符(81-68+1=14),所以要写
substr($0, 68, 14),而且得加个+0强制把截取的字符串转成数值,避免变成字符串拼接。
修正后的awk命令如下:
grep "^1" file.txt | awk '{ key = substr($0, 67, 1) val = substr($0, 68, 14) + 0 # 强制转数值,防止字符串拼接出错 s[key] += val } END { print "D=" s["D"], "C=" s["C"] }'
执行这个命令就能得到正确的结果:
D=1600 C=1600
2. 把结果赋值给shell变量
要把这两个值存到A和B里,用shell的read命令配合进程替换就能搞定:
read A B < <(grep "^1" file.txt | awk '{ key = substr($0, 67, 1) val = substr($0, 68, 14) + 0 s[key] += val } END { print s["D"], s["C"] }')
之后你直接用echo "D对应的和是$A,C对应的和是$B"就能验证,输出会是:
D对应的和是1600,C对应的和是1600
为啥之前结果错了?
之前的命令里,substr($0,68,83-68)是从第68位取15个字符(83-68=15),这就把后面的空格和其他无关数字也包含进去了,而且没转成数值,导致字符串拼接后变成了大数字,所以结果完全不对。加+0强制转数值就是为了避免这种问题。
内容的提问来源于stack exchange,提问作者user9794957
相关产品推荐
相关产品推荐

