在 pdb 文件的每 2-3-4 行使用 awk 和 sed 替换文本
Replace text using awk and sed at every 2-3-4 lines for pdb file
我有一个包含大约 200 000 行的 pdb 文本文件。每行看起来像这样:
COMPND
SOURCE
HETATM 1 CT 100 1 -23.207 17.632 14.543
HETATM 2 CT 99 1 -22.069 18.353 15.280
HETATM 3 OH 101 1 -21.074 18.762 14.358
HETATM 4 F 103 1 -23.816 18.483 13.675
HETATM 5 F 103 1 -24.119 17.162 15.433
HETATM 6 F 103 1 -22.680 16.591 13.841
HETATM 7 HC 104 1 -21.623 17.681 16.014
HETATM 8 HC 104 1 -22.451 19.218 15.823
HETATM 9 HO 102 1 -21.040 18.108 13.673
HETATM 10 CT 100 2 -4.340 -29.478 45.144
HETATM 11 CT 99 2 -3.051 -29.846 44.395
HETATM 12 OH 101 2 -1.968 -29.072 44.880
HETATM 13 F 103 2 -4.217 -29.778 46.464
HETATM 14 F 103 2 -5.396 -30.156 44.621
HETATM 15 F 103 2 -4.551 -28.140 45.015
HETATM 16 HC 104 2 -3.178 -29.656 43.329
HETATM 17 HC 104 2 -2.829 -30.908 44.511
HETATM 18 HO 102 2 -2.315 -28.222 45.119
HETATM 19 CT 100 3 -49.455 -17.542 -31.718
HETATM 20 CT 99 3 -49.981 -18.984 -31.736
HETATM 21 OH 101 3 -48.905 -19.897 -31.607
HETATM 22 F 103 3 -48.867 -17.273 -30.521
HETATM 23 F 103 3 -50.474 -16.668 -31.929
HETATM 24 F 103 3 -48.527 -17.405 -32.704
...
我必须将 C1 的所有第一个 CT 和 C2 的第二个 CT 更改为 H1、H2 的 F1、F2、F3 和 HC。
是否可以在小脚本中使用 awk 和 sed 更改它们?每个 C1-C2 和 F1、F2、F3 都是同一分子(三氟乙醇 - TFE)的一部分,但有许多 TFE 分子需要定义。
所以我希望它看起来像这样:
COMPND
SOURCE
HETATM 1 C1 100 1 -23.207 17.632 14.543
HETATM 2 C2 99 1 -22.069 18.353 15.280
HETATM 3 OH 101 1 -21.074 18.762 14.358
HETATM 4 F1 103 1 -23.816 18.483 13.675
HETATM 5 F2 103 1 -24.119 17.162 15.433
HETATM 6 F3 103 1 -22.680 16.591 13.841
HETATM 7 H1 104 1 -21.623 17.681 16.014
HETATM 8 H2 104 1 -22.451 19.218 15.823
HETATM 9 HO 102 1 -21.040 18.108 13.673
HETATM 10 C1 100 2 -4.340 -29.478 45.144
HETATM 11 C2 99 2 -3.051 -29.846 44.395
HETATM 12 OH 101 2 -1.968 -29.072 44.880
HETATM 13 F1 103 2 -4.217 -29.778 46.464
HETATM 14 F2 103 2 -5.396 -30.156 44.621
HETATM 15 F3 103 2 -4.551 -28.140 45.015
HETATM 16 H1 104 2 -3.178 -29.656 43.329
HETATM 17 H2 104 2 -2.829 -30.908 44.511
HETATM 18 HO 102 2 -2.315 -28.222 45.119
HETATM 19 C1 100 3 -49.455 -17.542 -31.718
HETATM 20 C2 99 3 -49.981 -18.984 -31.736
HETATM 21 OH 101 3 -48.905 -19.897 -31.607
HETATM 22 F1 103 3 -48.867 -17.273 -30.521
HETATM 23 F2 103 3 -50.474 -16.668 -31.929
HETATM 24 F3 103 3 -48.527 -17.405 -32.704
...
谢谢
这是解决此问题的一种方法 while read
循环,grep
和 sed
:
counter=0
while read line; do
# if a line has CT, CF, F in it...
if echo $line | grep -Pq '(CT|HC|F) '; then
# increment the counter and...
counter=$((counter+1))
# replace the 15th character with the counter!
echo $line | sed "s/./$counter/15"
else
# otherwise, reset the counter, and echo the line
counter=0
echo $line
fi
done < molecule.txt
然后您可以将其通过管道传输到另一个文件或标准输出!
你可以使用 awk
比 sed
更容易,但我毫不怀疑如果你真的想的话,它也可以在 sed
中完成。
您需要:
- 打印字段数为 1(或 2 — 小于 3)的行。
- 当至少有 3 列时,跟踪第 3 列中的最后一个值。
- 如果当前列是 CT、F 或 HC 之一:
- 如果第3列的最后一个值不同,将输入的第3列替换为首字母加1;记录下你输出的是1
- 否则,增加计数并输出第一个字母加上计数器。
- 否则输出行不变。
在文件 awk.script
中翻译成 awk
脚本可能是:
NF < 3 { print; next }
!= "CT" && != "F" && != "HC" { print; next }
{ if (old_col3 != ) { counter = 0 }
old_col3 =
= substr(, 1, 1) ++counter
print
}
并且,当您的数据文件中的 运行(非原创地命名为 data
)时,我得到:
$ awk -f awk.script data
COMPND
SOURCE
HETATM 1 C1 100 1 -23.207 17.632 14.543
HETATM 2 C2 99 1 -22.069 18.353 15.280
HETATM 3 OH 101 1 -21.074 18.762 14.358
HETATM 4 F1 103 1 -23.816 18.483 13.675
HETATM 5 F2 103 1 -24.119 17.162 15.433
HETATM 6 F3 103 1 -22.680 16.591 13.841
HETATM 7 H1 104 1 -21.623 17.681 16.014
HETATM 8 H2 104 1 -22.451 19.218 15.823
HETATM 9 HO 102 1 -21.040 18.108 13.673
HETATM 10 C1 100 2 -4.340 -29.478 45.144
HETATM 11 C2 99 2 -3.051 -29.846 44.395
HETATM 12 OH 101 2 -1.968 -29.072 44.880
HETATM 13 F1 103 2 -4.217 -29.778 46.464
HETATM 14 F2 103 2 -5.396 -30.156 44.621
HETATM 15 F3 103 2 -4.551 -28.140 45.015
HETATM 16 H1 104 2 -3.178 -29.656 43.329
HETATM 17 H2 104 2 -2.829 -30.908 44.511
HETATM 18 HO 102 2 -2.315 -28.222 45.119
HETATM 19 C1 100 3 -49.455 -17.542 -31.718
HETATM 20 C2 99 3 -49.981 -18.984 -31.736
HETATM 21 OH 101 3 -48.905 -19.897 -31.607
HETATM 22 F1 103 3 -48.867 -17.273 -30.521
HETATM 23 F2 103 3 -50.474 -16.668 -31.929
HETATM 24 F3 103 3 -48.527 -17.405 -32.704
$
这不会保留修改行中的所有间距,但在其他方面是您需要的。如果确实需要保留间距,则必须编写 printf()
语句来正确格式化字段(代替最后一段代码中的 print
:
printf("%s %4s %3s %4s %5s %11s %7s %7s\n", , , , , , , , );
这确实保留了间距,但总体上降低了代码的健壮性。它利用 属性 比 %ns
中的 n 短的字符串是右对齐的。结果:
COMPND
SOURCE
HETATM 1 C1 100 1 -23.207 17.632 14.543
HETATM 2 C2 99 1 -22.069 18.353 15.280
HETATM 3 OH 101 1 -21.074 18.762 14.358
HETATM 4 F1 103 1 -23.816 18.483 13.675
HETATM 5 F2 103 1 -24.119 17.162 15.433
HETATM 6 F3 103 1 -22.680 16.591 13.841
HETATM 7 H1 104 1 -21.623 17.681 16.014
HETATM 8 H2 104 1 -22.451 19.218 15.823
HETATM 9 HO 102 1 -21.040 18.108 13.673
HETATM 10 C1 100 2 -4.340 -29.478 45.144
HETATM 11 C2 99 2 -3.051 -29.846 44.395
HETATM 12 OH 101 2 -1.968 -29.072 44.880
HETATM 13 F1 103 2 -4.217 -29.778 46.464
HETATM 14 F2 103 2 -5.396 -30.156 44.621
HETATM 15 F3 103 2 -4.551 -28.140 45.015
HETATM 16 H1 104 2 -3.178 -29.656 43.329
HETATM 17 H2 104 2 -2.829 -30.908 44.511
HETATM 18 HO 102 2 -2.315 -28.222 45.119
HETATM 19 C1 100 3 -49.455 -17.542 -31.718
HETATM 20 C2 99 3 -49.981 -18.984 -31.736
HETATM 21 OH 101 3 -48.905 -19.897 -31.607
HETATM 22 F1 103 3 -48.867 -17.273 -30.521
HETATM 23 F2 103 3 -50.474 -16.668 -31.929
HETATM 24 F3 103 3 -48.527 -17.405 -32.704
因为当您达到 10,000 条记录时,HETATM
列和后面的数字列合并为一个列:
HETATM 21 OH 101 3 -48.905 -19.897 -31.607
…
HETATM 9999 HO 102 1111 -24.504 -16.257 -35.613
HETATM10000 CT 100 1112 9.045 23.978 29.038
HETATM10001 CT 99 1112 10.488 24.501 29.083
HETATM10002 OH 101 1112 11.370 23.545 28.522
HETATM10003 F 103 1112 8.650 23.804 27.749
HETATM10004 F 103 1112 8.209 24.855 29.654
HETATM10005 F 103 1112 8.996 22.779 29.679
不清楚当数字达到 100,000 及以上时会发生什么。但是,可以(在大多数情况下)通过计算列数并适当地工作来处理它。
NF < 7 { print; next }
NF == 8 && != "CT" && != "F" && != "HC" { print; next }
NF == 7 && != "CT" && != "F" && != "HC" { print; next }
NF == 8 {
if (old_mark != ) { counter = 0 }
old_mark =
= substr(, 1, 1) ++counter
printf("%s %4s %3s %4s %5s %11s %7s %7s\n", , , , , , , , );
}
NF == 7 {
if (old_mark != ) { counter = 0 }
old_mark =
= substr(, 1, 1) ++counter
printf("%s %3s %4s %5s %11s %7s %7s\n", , , , , , , );
}
注意 'column number neutral' 名称 old_mark
的使用。如果第 9,999 行包含 CT
并且第 10,000 行也包含 CT
,则映射需要是连续的(C1,C2)等。您可以使用:
NF < 7 { print; next }
NF == 8 && != "CT" && != "F" && != "HC" { print; next }
NF == 7 && != "CT" && != "F" && != "HC" { print; next }
{
colnum = NF - 5
if (old_mark != $colnum) { counter = 0 }
old_mark = $colnum
$colnum = substr($colnum, 1, 1) ++counter
if (NF == 7)
printf("%s %3s %4s %5s %11s %7s %7s\n", , , , , , , );
else
printf("%s %4s %3s %4s %5s %11s %7s %7s\n", , , , , , , , );
}
可能有一种方法可以使用一个 printf()
调用,但我怀疑是否值得这样做。
我有一个包含大约 200 000 行的 pdb 文本文件。每行看起来像这样:
COMPND
SOURCE
HETATM 1 CT 100 1 -23.207 17.632 14.543
HETATM 2 CT 99 1 -22.069 18.353 15.280
HETATM 3 OH 101 1 -21.074 18.762 14.358
HETATM 4 F 103 1 -23.816 18.483 13.675
HETATM 5 F 103 1 -24.119 17.162 15.433
HETATM 6 F 103 1 -22.680 16.591 13.841
HETATM 7 HC 104 1 -21.623 17.681 16.014
HETATM 8 HC 104 1 -22.451 19.218 15.823
HETATM 9 HO 102 1 -21.040 18.108 13.673
HETATM 10 CT 100 2 -4.340 -29.478 45.144
HETATM 11 CT 99 2 -3.051 -29.846 44.395
HETATM 12 OH 101 2 -1.968 -29.072 44.880
HETATM 13 F 103 2 -4.217 -29.778 46.464
HETATM 14 F 103 2 -5.396 -30.156 44.621
HETATM 15 F 103 2 -4.551 -28.140 45.015
HETATM 16 HC 104 2 -3.178 -29.656 43.329
HETATM 17 HC 104 2 -2.829 -30.908 44.511
HETATM 18 HO 102 2 -2.315 -28.222 45.119
HETATM 19 CT 100 3 -49.455 -17.542 -31.718
HETATM 20 CT 99 3 -49.981 -18.984 -31.736
HETATM 21 OH 101 3 -48.905 -19.897 -31.607
HETATM 22 F 103 3 -48.867 -17.273 -30.521
HETATM 23 F 103 3 -50.474 -16.668 -31.929
HETATM 24 F 103 3 -48.527 -17.405 -32.704
...
我必须将 C1 的所有第一个 CT 和 C2 的第二个 CT 更改为 H1、H2 的 F1、F2、F3 和 HC。
是否可以在小脚本中使用 awk 和 sed 更改它们?每个 C1-C2 和 F1、F2、F3 都是同一分子(三氟乙醇 - TFE)的一部分,但有许多 TFE 分子需要定义。
所以我希望它看起来像这样:
COMPND
SOURCE
HETATM 1 C1 100 1 -23.207 17.632 14.543
HETATM 2 C2 99 1 -22.069 18.353 15.280
HETATM 3 OH 101 1 -21.074 18.762 14.358
HETATM 4 F1 103 1 -23.816 18.483 13.675
HETATM 5 F2 103 1 -24.119 17.162 15.433
HETATM 6 F3 103 1 -22.680 16.591 13.841
HETATM 7 H1 104 1 -21.623 17.681 16.014
HETATM 8 H2 104 1 -22.451 19.218 15.823
HETATM 9 HO 102 1 -21.040 18.108 13.673
HETATM 10 C1 100 2 -4.340 -29.478 45.144
HETATM 11 C2 99 2 -3.051 -29.846 44.395
HETATM 12 OH 101 2 -1.968 -29.072 44.880
HETATM 13 F1 103 2 -4.217 -29.778 46.464
HETATM 14 F2 103 2 -5.396 -30.156 44.621
HETATM 15 F3 103 2 -4.551 -28.140 45.015
HETATM 16 H1 104 2 -3.178 -29.656 43.329
HETATM 17 H2 104 2 -2.829 -30.908 44.511
HETATM 18 HO 102 2 -2.315 -28.222 45.119
HETATM 19 C1 100 3 -49.455 -17.542 -31.718
HETATM 20 C2 99 3 -49.981 -18.984 -31.736
HETATM 21 OH 101 3 -48.905 -19.897 -31.607
HETATM 22 F1 103 3 -48.867 -17.273 -30.521
HETATM 23 F2 103 3 -50.474 -16.668 -31.929
HETATM 24 F3 103 3 -48.527 -17.405 -32.704
...
谢谢
这是解决此问题的一种方法 while read
循环,grep
和 sed
:
counter=0
while read line; do
# if a line has CT, CF, F in it...
if echo $line | grep -Pq '(CT|HC|F) '; then
# increment the counter and...
counter=$((counter+1))
# replace the 15th character with the counter!
echo $line | sed "s/./$counter/15"
else
# otherwise, reset the counter, and echo the line
counter=0
echo $line
fi
done < molecule.txt
然后您可以将其通过管道传输到另一个文件或标准输出!
你可以使用 awk
比 sed
更容易,但我毫不怀疑如果你真的想的话,它也可以在 sed
中完成。
您需要:
- 打印字段数为 1(或 2 — 小于 3)的行。
- 当至少有 3 列时,跟踪第 3 列中的最后一个值。
- 如果当前列是 CT、F 或 HC 之一:
- 如果第3列的最后一个值不同,将输入的第3列替换为首字母加1;记录下你输出的是1
- 否则,增加计数并输出第一个字母加上计数器。
- 否则输出行不变。
在文件 awk.script
中翻译成 awk
脚本可能是:
NF < 3 { print; next }
!= "CT" && != "F" && != "HC" { print; next }
{ if (old_col3 != ) { counter = 0 }
old_col3 =
= substr(, 1, 1) ++counter
print
}
并且,当您的数据文件中的 运行(非原创地命名为 data
)时,我得到:
$ awk -f awk.script data
COMPND
SOURCE
HETATM 1 C1 100 1 -23.207 17.632 14.543
HETATM 2 C2 99 1 -22.069 18.353 15.280
HETATM 3 OH 101 1 -21.074 18.762 14.358
HETATM 4 F1 103 1 -23.816 18.483 13.675
HETATM 5 F2 103 1 -24.119 17.162 15.433
HETATM 6 F3 103 1 -22.680 16.591 13.841
HETATM 7 H1 104 1 -21.623 17.681 16.014
HETATM 8 H2 104 1 -22.451 19.218 15.823
HETATM 9 HO 102 1 -21.040 18.108 13.673
HETATM 10 C1 100 2 -4.340 -29.478 45.144
HETATM 11 C2 99 2 -3.051 -29.846 44.395
HETATM 12 OH 101 2 -1.968 -29.072 44.880
HETATM 13 F1 103 2 -4.217 -29.778 46.464
HETATM 14 F2 103 2 -5.396 -30.156 44.621
HETATM 15 F3 103 2 -4.551 -28.140 45.015
HETATM 16 H1 104 2 -3.178 -29.656 43.329
HETATM 17 H2 104 2 -2.829 -30.908 44.511
HETATM 18 HO 102 2 -2.315 -28.222 45.119
HETATM 19 C1 100 3 -49.455 -17.542 -31.718
HETATM 20 C2 99 3 -49.981 -18.984 -31.736
HETATM 21 OH 101 3 -48.905 -19.897 -31.607
HETATM 22 F1 103 3 -48.867 -17.273 -30.521
HETATM 23 F2 103 3 -50.474 -16.668 -31.929
HETATM 24 F3 103 3 -48.527 -17.405 -32.704
$
这不会保留修改行中的所有间距,但在其他方面是您需要的。如果确实需要保留间距,则必须编写 printf()
语句来正确格式化字段(代替最后一段代码中的 print
:
printf("%s %4s %3s %4s %5s %11s %7s %7s\n", , , , , , , , );
这确实保留了间距,但总体上降低了代码的健壮性。它利用 属性 比 %ns
中的 n 短的字符串是右对齐的。结果:
COMPND
SOURCE
HETATM 1 C1 100 1 -23.207 17.632 14.543
HETATM 2 C2 99 1 -22.069 18.353 15.280
HETATM 3 OH 101 1 -21.074 18.762 14.358
HETATM 4 F1 103 1 -23.816 18.483 13.675
HETATM 5 F2 103 1 -24.119 17.162 15.433
HETATM 6 F3 103 1 -22.680 16.591 13.841
HETATM 7 H1 104 1 -21.623 17.681 16.014
HETATM 8 H2 104 1 -22.451 19.218 15.823
HETATM 9 HO 102 1 -21.040 18.108 13.673
HETATM 10 C1 100 2 -4.340 -29.478 45.144
HETATM 11 C2 99 2 -3.051 -29.846 44.395
HETATM 12 OH 101 2 -1.968 -29.072 44.880
HETATM 13 F1 103 2 -4.217 -29.778 46.464
HETATM 14 F2 103 2 -5.396 -30.156 44.621
HETATM 15 F3 103 2 -4.551 -28.140 45.015
HETATM 16 H1 104 2 -3.178 -29.656 43.329
HETATM 17 H2 104 2 -2.829 -30.908 44.511
HETATM 18 HO 102 2 -2.315 -28.222 45.119
HETATM 19 C1 100 3 -49.455 -17.542 -31.718
HETATM 20 C2 99 3 -49.981 -18.984 -31.736
HETATM 21 OH 101 3 -48.905 -19.897 -31.607
HETATM 22 F1 103 3 -48.867 -17.273 -30.521
HETATM 23 F2 103 3 -50.474 -16.668 -31.929
HETATM 24 F3 103 3 -48.527 -17.405 -32.704
因为当您达到 10,000 条记录时,HETATM
列和后面的数字列合并为一个列:
HETATM 21 OH 101 3 -48.905 -19.897 -31.607
…
HETATM 9999 HO 102 1111 -24.504 -16.257 -35.613
HETATM10000 CT 100 1112 9.045 23.978 29.038
HETATM10001 CT 99 1112 10.488 24.501 29.083
HETATM10002 OH 101 1112 11.370 23.545 28.522
HETATM10003 F 103 1112 8.650 23.804 27.749
HETATM10004 F 103 1112 8.209 24.855 29.654
HETATM10005 F 103 1112 8.996 22.779 29.679
不清楚当数字达到 100,000 及以上时会发生什么。但是,可以(在大多数情况下)通过计算列数并适当地工作来处理它。
NF < 7 { print; next }
NF == 8 && != "CT" && != "F" && != "HC" { print; next }
NF == 7 && != "CT" && != "F" && != "HC" { print; next }
NF == 8 {
if (old_mark != ) { counter = 0 }
old_mark =
= substr(, 1, 1) ++counter
printf("%s %4s %3s %4s %5s %11s %7s %7s\n", , , , , , , , );
}
NF == 7 {
if (old_mark != ) { counter = 0 }
old_mark =
= substr(, 1, 1) ++counter
printf("%s %3s %4s %5s %11s %7s %7s\n", , , , , , , );
}
注意 'column number neutral' 名称 old_mark
的使用。如果第 9,999 行包含 CT
并且第 10,000 行也包含 CT
,则映射需要是连续的(C1,C2)等。您可以使用:
NF < 7 { print; next }
NF == 8 && != "CT" && != "F" && != "HC" { print; next }
NF == 7 && != "CT" && != "F" && != "HC" { print; next }
{
colnum = NF - 5
if (old_mark != $colnum) { counter = 0 }
old_mark = $colnum
$colnum = substr($colnum, 1, 1) ++counter
if (NF == 7)
printf("%s %3s %4s %5s %11s %7s %7s\n", , , , , , , );
else
printf("%s %4s %3s %4s %5s %11s %7s %7s\n", , , , , , , , );
}
可能有一种方法可以使用一个 printf()
调用,但我怀疑是否值得这样做。