Sed 模式匹配在替换字符串中使用行号的偏移量?
Sed Pattern Match Which Uses Offset of Line Number in the Replace String?
我有一个列字段类型标准的文件(其中字符 1
到 6
对应于 field 1
,7
到 11
到 field 2
,依此类推)。
关键属性是:
- 每行
80
个字符长。
field 2
到 field N
中的文本总是
right
场内有理。
我有一个这样的文件:
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
记录...前六个原子等于该字符串的行...我想替换第二个字段中的数字(字符 7
到 11
)条目编号,以 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 编辑为递增的数字。
我有一个列字段类型标准的文件(其中字符 1
到 6
对应于 field 1
,7
到 11
到 field 2
,依此类推)。
关键属性是:
- 每行
80
个字符长。 field 2
到field N
中的文本总是right
场内有理。
我有一个这样的文件:
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
记录...前六个原子等于该字符串的行...我想替换第二个字段中的数字(字符 7
到 11
)条目编号,以 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 编辑为递增的数字。