如何使用 Sed 命令将第 4 列中的 A 替换为 RA? (这些列之间包含多个空格)
ATOM 32 P A 2 6.882 -5.338 6.560 1.00 0.00 P
ATOM 33 OP1 A 2 7.505 -5.970 7.750 1.00 0.00 O
ATOM 34 OP2 A 2 5.404 -5.201 6.610 1.00 0.00 O
TER
可以通过awk '{gsub("A","RA",$4)}1' a.txt > b.txt
答案1
由于间距必须保持固定,也许这意味着整个布局是固定的,然后这可能就是您正在寻找的使用支持 -E 的 sed 来启用 ERE,例如 GNU sed 或 OSX/BSD sed:
$ sed -E 's/(.{17})A /\1RA/' file
ATOM 32 P RA 2 6.882 -5.338 6.560 1.00 0.00 P
ATOM 33 OP1 RA 2 7.505 -5.970 7.750 1.00 0.00 O
ATOM 34 OP2 RA 2 5.404 -5.201 6.610 1.00 0.00 O
TER
或使用任何 POSIX sed:
$ sed 's/\(.\{17\}\)A /\1RA/' file
ATOM 32 P RA 2 6.882 -5.338 6.560 1.00 0.00 P
ATOM 33 OP1 RA 2 7.505 -5.970 7.750 1.00 0.00 O
ATOM 34 OP2 RA 2 5.404 -5.201 6.610 1.00 0.00 O
TER
编辑:您的输入似乎不符合PDB标准@bushman 之前发布过,但如果确实如此,您可以使用以下方法使用标准中的信息f[]
按标签/名称创建字段数组,按标签/名称修改它们(而不是它们在输入中的相对位置) ),并以相同的固定宽度格式打印它们:
$ cat tst.awk
BEGIN {
# Record Format (copied from http://www.wwpdb.org/documentation/file-format-content/format33/sect9.html#ATOM)
#
# COLUMNS DATA TYPE FIELD DEFINITION
# -------------------------------------------------------------------------------------
flds[++numFlds]=" 1 - 6 Record name ATOM "
flds[++numFlds]=" 7 - 11 Integer serial Atom serial number."
flds[++numFlds]=" 13 - 16 Atom name Atom name."
flds[++numFlds]=" 17 Character altLoc Alternate location indicator."
flds[++numFlds]=" 18 - 20 Residue name resName Residue name."
flds[++numFlds]=" 22 Character chainID Chain identifier."
flds[++numFlds]=" 23 - 26 Integer resSeq Residue sequence number."
flds[++numFlds]=" 27 AChar iCode Code for insertion of residues."
flds[++numFlds]=" 31 - 38 Real(8.3) x Orthogonal coordinates for X in Angstroms."
flds[++numFlds]=" 39 - 46 Real(8.3) y Orthogonal coordinates for Y in Angstroms."
flds[++numFlds]=" 47 - 54 Real(8.3) z Orthogonal coordinates for Z in Angstroms."
flds[++numFlds]=" 55 - 60 Real(6.2) occupancy Occupancy."
flds[++numFlds]=" 61 - 66 Real(6.2) tempFactor Temperature factor."
flds[++numFlds]=" 77 - 78 LString(2) element Element symbol, right-justified."
flds[++numFlds]=" 79 - 80 LString(2) charge Charge on the atom."
for (fldNr=1; fldNr<=numFlds; fldNr++) {
fld = flds[fldNr]
cols = substr(fld,1,16)
gsub(/ /,"",cols)
n = split(cols,begEnd,/-/)
tag = substr(fld,31,13)
gsub(/ /,"",tag)
tags[fldNr] = tag
begs[tag] = begEnd[1]
wids[tag] = begEnd[n] - begEnd[1] + 1
# Uncomment this if interested in the values the arrays contain:
# print "<" fldNr "><" tags[fldNr] "><" begs[tag] "><" wids[tag] ">" | "cat>&2"
}
}
{
for (fldNr=1; fldNr<=numFlds; fldNr++) {
tag = tags[fldNr]
f[tag] = substr($0,begs[tag],wids[tag])
gsub(/^ +| +$/,"",f[tag])
}
}
f["resName"] == "A" { f["resName"] = "RA" } # this is where you can change a field by its tag/name
{
for (fldNr=1; fldNr<=numFlds; fldNr++) {
tag = tags[fldNr]
printf "%-*s", wids[tag], f[tag]
}
print ""
}
$
$ awk -f tst.awk file
ATOM 32 P RA 2 6.882 -5.338 6.560 1.00 0.00 P
ATOM 33 OP1 RA 2 7.505 -5.970 7.750 1.00 0.00 O
ATOM 34 OP2 RA 2 5.404 -5.201 6.610 1.00 0.00 O
TER
显然,这对于您现在正在尝试做的事情来说有点矫枉过正,但这是一个需要牢记的好通用方法,它解决了您在您感兴趣的字段之前讨论的任何其他方法可能遇到的问题。
答案2
使用sed
sed -E "s/^(([^ ]+ +){3})A /\1RA /" file1
演练
从输入行开始^
([^ ] +)
表示将一组捕获( )
为连续的非空格字符序列,[^ ]+
后跟另一个连续的空格序列+
抓住这个组的重复{3}
,所以下一个字符将出现在你的第四个字段中
通过包裹将所有这三个重复组合在一起( )
如果现在存储的“超级组”\1
后面跟着A
(即带有 2 个空格的 A),则将其替换为\1RA
(即只有 1 个尾随空格,因此您保持字符数相同)
答案3
如果您只是希望通过列替换生成漂亮的打印表格输出,则在命令中添加以下内容awk
即可实现此目的:
awk ' gsub("A","RA",$4){for (i=1;i<=NF;i++){printf("%-9s",$i)}print "" }' a.txt > b.txt
输出cat b.txt
如下:
ATOM 32 P RA 2 6.882 -5.338 6.560 1.00 0.00 P
ATOM 33 OP1 RA 2 7.505 -5.970 7.750 1.00 0.00 O
ATOM 34 OP2 RA 2 5.404 -5.201 6.610 1.00 0.00 O
如果您正在寻找每列之间更具体的间距,则必须放弃循环printf
并为每个字段分配单独的间距。
如果您正在寻找一种非常快速的sed
替代方案,您始终可以这样做:
sed 's/ A /RA/' a.txt > b.txt
但这将用“RA”替换文件中的每个“A”,不限于第四列,因为sed
使用与 不同的字段分割方法awk
。尽管如此,使用上面的sed
命令将会得到cat b.txt
如下所示的结果:
ATOM 32 P RA 2 6.882 -5.338 6.560 1.00 0.00 P
ATOM 33 OP1 RA 2 7.505 -5.970 7.750 1.00 0.00 O
ATOM 34 OP2 RA 2 5.404 -5.201 6.610 1.00 0.00 O
答案4
方法 1:不带反向引用的 GNU sed
$ sed -re '
h
s/\S+/\n&\n/4
s/\nA\n/RA/;t
g
' file
方法 2:带有反向引用的 GNU sed。
$ sed -re '
s/^(\s*(\S+\s+){3})(A(\s|$))/\1R\3/
' file
请注意,这两种 sed 解决方案都可以兼容 Posix,但它们会以代码清晰度为代价,并可能导致反斜杠炎。
方法 3:Perl 使用类似 awk 的字段,但有一点不同,这个字段既存储字段值又存储分隔符。因此,第 4 个字段变为第 8 个字段,如果使用零索引数组,则为 7。
$ perl -F'/(\S+)/' -lane '
$F[7] =~ s/^A$/RA/;
print @F;\
' file