如何在Bash中为特定OHH行组上方插入FRAGNAME=H2ODFT行?
问题描述
我是Bash脚本新手,之前用下面的命令能在所有以O开头的行前插入FRAGNAME=H2ODFT:
for EFP in *.inp; do sed -i "/^O */i FRAGNAME=H2ODFT" $EFP done
但现在需要仅在连续的O、H、H三行(带笛卡尔坐标)前插入该行,而非所有O行。试了sed多行匹配没效果:
for FILE in *.inp; do sed -i "/^O*\nH*\nH */i FRAGNAME=H2ODFT" $EFP done
还试过awk也没成功。
输入示例:
C 36.116 34.950 34.657 C 35.638 34.681 35.883 ...(省略部分内容) O 40.889 37.054 35.401 H 40.304 36.361 35.706 H 41.620 36.587 34.995
期望输出:
...(省略部分内容) FRAGNAME=H2ODFT O 40.889 37.054 35.401 H 40.304 36.361 35.706 H 41.620 36.587 34.995
可行解决方法
方法1:GNU Sed 多行匹配
sed默认单行处理,需要通过N命令读取后续行构建多行匹配,以下命令可实现需求:
for EFP in *.inp; do sed -i -E 'N;N;/^[[:space:]]*O[[:space:]]+.+\n[[:space:]]*H[[:space:]]+.+\n[[:space:]]*H[[:space:]]+/i FRAGNAME=H2ODFT' "$EFP" done
-E:启用扩展正则,简化匹配语法N;N:读取当前行之后的两行,将三行内容放入模式空间- 正则部分精准匹配"空格+O+坐标"→换行→"空格+H+坐标"→换行→"空格+H+坐标"的结构
i命令在匹配到的行组前插入指定文本
方法2:Awk 缓存行处理
awk处理多行逻辑更直观,通过缓存最近三行内容检测OHH序列:
for EFP in *.inp; do awk ' { line1 = line2 line2 = current current = $0 } /^[[:space:]]*H/ && line1 ~ /^[[:space:]]*O/ && line2 ~ /^[[:space:]]*H/ { print " FRAGNAME=H2ODFT" print line1 print line2 } NR>2 { print current } NR<=2 { if (NR==2) print line1; if (NR==1) print current } ' "$EFP" > temp.inp && mv temp.inp "$EFP" done
- 用
line1/line2/current三个变量缓存最近三行 - 检测到连续OHH时,先插入目标行,再输出缓存的O和H行
- 最后处理剩余行,确保所有内容完整输出
- 由于awk无法直接修改原文件,先输出到临时文件再替换原文件
方法3:GNU Sed -z 参数(简洁版)
GNU Sed的-z参数可将整个文件读入内存,支持全局多行替换:
for EFP in *.inp; do sed -i -z 's/^[[:space:]]*O[[:space:]]+.+\n[[:space:]]*H[[:space:]]+.+\n[[:space:]]*H[[:space:]]+/ FRAGNAME=H2ODFT\n&/mg' "$EFP" done
-z:将文件视为单字符串处理- 替换规则中,
&指代匹配到的OHH行组,在其前插入目标行和换行符 mg:开启多行匹配和全局替换模式
内容的提问来源于stack exchange,提问作者Lucielle
相关产品推荐
相关产品推荐

