如何在Bash中仅对$EFRAG后的行修改列并添加标签?
处理分子坐标文件的Bash脚本方案
问题描述
原始输入文件内容:
H 1 2 3 4 H 1 2 3 4 C 1 2 3 4 $END $EFRAG COORD=CART FRAGNAME=H2ODFT O 1 2 3 4 H 1 2 3 4 H 1 2 3 4 FRAGNAME=H2ODFT O 1 2 3 4 H 1 2 3 4 H 1 2 3 4
需要实现的修改:
$EFRAG行之前的内容保持不变$EFRAG行之后的内容:- 删除坐标行中的第二列(即那个
1) - 对每个
FRAGNAME=H2ODFT后的三个原子行,分别给O加a、第一个H加b、第二个H加c标签
- 删除坐标行中的第二列(即那个
预期输出:
H 1 2 3 4 H 1 2 3 4 C 1 2 3 4 $END $EFRAG COORD=CART FRAGNAME=H2ODFT Oa 2 3 4 Hb 2 3 4 Hc 2 3 4 FRAGNAME=H2ODFT Oa 2 3 4 Hb 2 3 4 Hc 2 3 4
解决方案:使用Awk脚本
Awk天生适合这种按行处理且需要状态切换的场景,单命令就能完成所有需求:
awk ' # 标记是否进入$EFRAG之后的处理区域 /^\s*\$EFRAG/ { in_efrag=1; print; next } # 未进入EFRAG区域时直接输出原内容 !in_efrag { print; next } # 进入EFRAG区域后的具体处理 { # 遇到FRAGNAME行,重置原子计数并直接输出 if (/FRAGNAME=/) { cnt=0; print; next } # COORD行直接输出 if (/COORD=/) { print; next } # 处理原子行:计数递增,匹配对应标签,跳过第二列输出 cnt++ tag = (cnt==1) ? "a" : (cnt==2) ? "b" : "c" printf "%s%s %s %s %s\n", $1, tag, $3, $4, $5 } ' input_file > output_file
脚本逐行解释
- 状态切换:用
in_efrag变量区分$EFRAG前后的内容,之前的行直接原样输出 - 片段初始化:每次遇到
FRAGNAME=H2ODFT就重置计数器cnt,确保每个片段内的原子标签循环正确 - 原子行处理:
cnt记录当前片段内的原子顺序(1对应O,2对应第一个H,3对应第二个H)- 根据
cnt值匹配a/b/c标签,拼接到原子符号末尾 - 跳过第二列(
$2),直接输出剩余坐标列,保持格式对齐
关于Sed+Grep的说明
你之前考虑的Sed+Grep组合虽然能实现,但因为需要跟踪片段内的原子顺序,Sed的状态管理会非常繁琐,代码可读性差,不适合新手调试。Awk的方案更直观,也更容易修改扩展。
内容的提问来源于stack exchange,提问作者Lucielle
相关产品推荐
相关产品推荐

