如何仅对文本文件第一列偏移指定值 保留其余列与原有格式
问题说明
需要处理多列文本数据文件,规则如下:
- 仅对第一列所有数值统一加上固定偏移量(示例偏移值为-0.01,即第一列数值统一减0.01)
- 其余所有列数据完全保持不变
- 不能修改原有数值格式,例如
10.0000减去10后必须输出0.0000,不能省略小数位输出为0 - 现有实现需要手动枚举所有列号,当列数较多时写法繁琐,需要更简便的通用方案
现有实现脚本:
cat test.dat | awk '{print $1-0.01, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27}'
示例输入文件内容:
-0.4122 50.0000 59.19254908 0.20390966E+21 0.50210854E+04 0.10024552E+05 0.50210854E+04 0.20390966E+21 0.12781341E+05 0.10024552E+05 0.12781341E+05 0.17430806E+21 -0.13971462E-04 -0.34940712E-21 -0.84283159E-21 -0.34940712E-21 -0.13971462E-04 -0.10333849E-20 0.73796435E-22 0.12933410E-21 -0.30127810E-04 0.22653580E+15 0.43388767E-02 0.12519835E-01 0.43388767E-02 0.22653580E+15 0.15837399E-01 0.12519835E-01 0.15837399E-01 0.21852932E+15 -0.4235 100.0000 59.19127436 0.19338258E+21 0.41823435E+04 0.10186550E+05 0.41823435E+04 0.19338258E+21 0.12893514E+05 0.10186550E+05 0.12893514E+05 0.17755002E+21 -0.90933331E-05 -0.21562030E-21 -0.62836171E-21 -0.21562030E-21 -0.90933331E-05 -0.61018803E-21 -0.48935277E-22 0.10805572E-21 -0.19116589E-04 0.44412500E+15 0.74492273E-02 0.26238884E-01 0.74492273E-02 0.44412500E+15 0.32779761E-01 0.26238884E-01 0.32779761E-01 0.46142213E+15 -0.4620 150.0000 59.19108585 0.18970962E+21 0.38138923E+04 0.10378024E+05 0.38138923E+04 0.18970962E+21 0.13078457E+05 0.10378024E+05 0.13078457E+05 0.18150561E+21 -0.70829346E-05 -0.23441645E-21 -0.40816670E-21 -0.23441645E-21 -0.70829346E-05 -0.31840202E-21 -0.91970004E-22 0.71596380E-22 -0.12540327E-04 0.68630757E+15 0.12171742E-01 0.40052678E-01 0.12171742E-01 0.68630757E+15 0.50206970E-01 0.40052678E-01 0.50206970E-01 0.71030708E+15
简便实现方案
根据对输出格式的要求不同,可以选择以下两种方案,都不需要手动枚举所有列号,适配任意列数的文件:
方案1:awk实现(列间用单个空格分隔,自动保留第一列小数位)
这个方案会自动识别第一列原始的小数位数,计算偏移后输出相同小数位数的结果,其余列数值原样输出,列之间统一用单个空格分隔。
# 修改-v off=0.01里的数值即可调整偏移量 awk -v off=0.01 ' match($1, /\.([0-9]+)/, dec) { fmt = "%." length(dec[1]) "f" } { printf fmt, $1 - off for(i=2; i<=NF; i++) printf " %s", $i print "" }' test.dat
如果不需要保留第一列的尾随零,只是要数值正确,可以用更短的写法:
awk -v off=0.01 '{$1 = $1 - off; print $0}' test.dat
方案2:Perl实现(完全保留原始文件格式)
如果要求除了第一列的数值之外,后面所有内容(包括列之间的多空格缩进、其他列的科学计数法格式、特殊字符)完全和原文件一致,用这个方案:
# 修改代码里的0.01即可调整偏移量 perl -pe 's/^(\s*-?)(\d+\.(\d+))/$1 . sprintf("%.%df", $2 - 0.01, length($3))/e' test.dat
这个方案只会匹配每行开头的第一个浮点数做偏移计算,不会修改行内其他任何字符,格式还原度100%。
注:原写法里的
cat test.dat | awk属于多余的管道操作,awk本身就支持直接传入文件名读取,省去cat进程效率更高。
内容的提问来源于stack exchange,提问作者kcb
相关产品推荐
相关产品推荐

