Sed 模式匹配在替换字符串中使用行号的偏移量?

Sed Pattern Match Which Uses Offset of Line Number in the Replace String?

我有一个列字段类型标准的文件(其中字符 16 对应于 field 1711field 2,依此类推)。

关键属性是:

我有一个这样的文件:

REMARK   1 
HETATM    1
HETATM    5
HETATM    6
HETATM    7
HETATM    9
HETATM   12
HETATM   15
HETATM   19
HETATM   23
HETATM   27
HETATM   30
HETATM   34
HETATM   38
END

对于 HETATM 记录...前六个原子等于该字符串的行...我想替换第二个字段中的数字(字符 711)条目编号,以 1.

开头

即我希望输出显示为:

REMARK   1 
HETATM    1
HETATM    2
HETATM    3
HETATM    4
HETATM    5
HETATM    6
HETATM    7
HETATM    8
HETATM    9
HETATM   10
HETATM   11
HETATM   12
HETATM   13
END

目前我最简洁的解决方案(使用临时文件进行测试,避免搞砸我原来的)是:

#!/bin/bash
f=file.pdb
fTmp=${f}.tmp
cp $f $fTmp
for ((l=1; l<$( wc -l $fTmp | awk '{print }' ); l++)); do
   sed -i "$((l + 1))"'s#\(HETATM\)[ 0-9]\{5\}#'"$( printf '%5s' $l )"'#g' $fTmp
done
cat $fTmp
rm $fTmp

删除临时文件包这就变成了:

f=file.pdb
for ((l=1; l<$( wc -l $f | awk '{print }' ); l++)); do
   sed -i "$((l + 1))"'s#\(HETATM\)[ 0-9]\{5\}#'"$( printf '%5s' $l )"'#g' $f
done

似乎应该有某种方法可以在 sed 中使用行号来创建更简洁的解决方案——也许是单个 sed -i 命令。假设这是可能的,唯一的复杂性是需要一些算术运算——应该设置为 1 的第一个匹配项总是出现在第二行。

我希望有 sed 解决方案。我对使用 awk 犹豫不决,因为 space 填充很重要并且需要内联编辑,看来 sed 是更好的选择。

请注意,一旦我有了经过验证有效的改进解决方案,我将扔掉 *.tmp 文件内容,直接在目标文件上操作,因此单个 sed -i 命令可能完成任务。

如果您有 GNU awk,您可以指定您的输入是固定宽度的字段。例如,

awk -v OFS='' -v FIELDWIDTHS='6 5 6 6 6 6 6' '
/^HETATM/{  = sprintf("%5d",++count) };1' file.pdb

这会将宽度为 5 的字段 2 编辑为递增的数字。