如何用AWK替换指定条件列内容并保持文件原始格式?
问题:AWK替换列内容时保留原始固定宽度排版
需求描述
需要用AWK将输入文件中第三列等于"AAA"的行的第11列内容替换为"0.400",同时保持文件原有的固定宽度排版格式。
输入示例
ATOM 1 AAA ABC 1 -60.638 44.587 36.897 0.00 0.00 0.232 A ATOM 2 BB ABC 1 59.675 45.544 36.863 0.00 0.00 -0.252 BB ATOM 3 CCC ABC 1 59.127 -45.567 35.637 0.00 0.00 0.145 C ATOM 4 DD ABC 1 59.791 44.664 34.873 0.00 0.00 0.055 D ATOM 5 EEE ABC 1 60.801 44.256 35.627 0.00 0.00 -0.245 E ... ATOM 14996 AAA ABC 1 80.638 44.387 76.897 0.00 0.00 0.232 A ATOM 14997 BB ABC 1 19.675 -25.544 66.863 0.00 0.00 -0.252 BB ATOM 14998 CCC ABC 1 89.127 75.567 35.637 0.00 0.00 0.145 C ATOM 14999 DD ABC 1 -29.791 34.664 -54.873 0.00 0.00 0.055 D ATOM 15000 EEE ABC 1 90.801 74.256 25.627 0.00 0.00 -0.245 E
原有问题
使用命令 awk '$3 == "AAA" {$11= 0.400}1' file 可以完成替换,但AWK默认会用单个空格作为输出字段分隔符(OFS),破坏了原有的多空格固定宽度格式,输出结果如下:
ATOM 1 AAA ABC 1 -60.638 44.587 36.897 0.00 0.00 0.4 A ATOM 2 BB ABC 1 59.675 45.544 36.863 0.00 0.00 -0.252 BB ATOM 3 CCC ABC 1 59.127 -45.567 35.637 0.00 0.00 0.145 C ATOM 4 DD ABC 1 59.791 44.664 34.873 0.00 0.00 0.055 D ATOM 5 EEE ABC 1 60.801 44.256 35.627 0.00 0.00 -0.245 E
期望输出
ATOM 1 AAA ABC 1 -60.638 44.587 36.897 0.00 0.00 0.400 A ATOM 2 BB ABC 1 59.675 45.544 36.863 0.00 0.00 -0.252 BB ATOM 3 CCC ABC 1 59.127 -45.567 35.637 0.00 0.00 0.145 C ATOM 4 DD ABC 1 59.791 44.664 34.873 0.00 0.00 0.055 D ATOM 5 EEE ABC 1 60.801 44.256 35.627 0.00 0.00 -0.245 E
解决方案
使用printf配合格式控制符,按照原文件的固定宽度重新格式化每一行,确保替换后格式一致:
{ # 确定第11列的值:如果第三列是AAA则用0.400,否则保留原值 target_val = ($3 == "AAA") ? 0.4 : $11 # 按照原格式输出所有字段,每个字段对应固定宽度和格式 printf "%-8s%6d %4s %4s%6d %8.3f %8.3f %8.3f %6.2f %6.2f%8.3f %2s\n", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, target_val, $12 }
命令解释
%-8s:第一列(ATOM)左对齐,占8位,匹配原格式中ATOM后跟随4个空格的排版%6d:第二列(原子序号)右对齐,占6位,适配1到15000的序号长度%4s:第三、四列(原子名、残基名)占4位,保留原有的空格填充%8.3f:第六到八列(坐标值)右对齐,占8位,保留三位小数%6.2f:第九、十列(Occupancy、Temp factor)右对齐,占6位,保留两位小数%8.3f:目标列(第11列)右对齐,占8位,保留三位小数,确保替换后的"0.400"格式正确%2s:最后一列(元素符号)占2位,匹配原格式
另一种方法:基于字符串位置替换
如果明确目标字段在原字符串中的位置,也可以用substr直接替换对应区域,避免字段拆分:
$3 == "AAA" { # 生成格式正确的目标值 new_val = sprintf("%8.3f", 0.4) # 假设目标字段从第65位开始,长度8位,替换该区域 $0 = substr($0, 1, 64) new_val substr($0, 73) } 1
注意:需要根据实际文件的字段位置调整
substr的起始和结束索引,该方法更适合固定宽度格式的精确操作。
内容的提问来源于stack exchange,提问作者user19619903
相关产品推荐
相关产品推荐

