2015-05-14 38 views
1

我有一个大约200 000行的pdb文本文件。每行看起来是这样的:使用awk和sed在每2-3-4行代替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,与同为F1,F2,F3和HC到H1,H2。

是否可以使用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 
... 

感谢

回答

1

您可以比sed更容易使用awk,但如果您真的想的话,我毫不怀疑它也可以在sed中完成。

您需要:

  • 打印线,其中字段的数目是1(或大于3 2 —更少)。
  • 当至少有3列时,跟踪第3列中的最后一个值。
  • 如果当前列是CT,F的一种或HC:
    • 如果在第3列的最后一个值是不同的,代替与所述第一个字母加1的输入栏3;记录它是你输出的1。
    • 否则,递增计数并输出第一个字母加上计数器。
  • 否则输出该行不变。

这被翻译成awk脚本文件,awk.script,可能是:

NF < 3 { print; next } 
$3 != "CT" && $3 != "F" && $3 != "HC" { print; next } 
{ if (old_col3 != $3) { counter = 0 } 
    old_col3 = $3 
    $3 = substr($3, 1, 1) ++counter 
    print 
} 

而且,当是对数据文件运行(命名,unoriginally,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", $1, $2, $3, $4, $5, $6, $7, $8); 

这并保持间距,反而使得代码通常不够健壮,它利用比在%ns中的字符串右对齐的属性。这产生了:

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 

由于看来,当你得到了10000条记录,在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 && $3 != "CT" && $3 != "F" && $3 != "HC" { print; next } 
NF == 7 && $2 != "CT" && $2 != "F" && $2 != "HC" { print; next } 
NF == 8 { 
      if (old_mark != $3) { counter = 0 } 
      old_mark = $3 
      $3 = substr($3, 1, 1) ++counter 
      printf("%s %4s %3s %4s %5s %11s %7s %7s\n", $1, $2, $3, $4, $5, $6, $7, $8); 
     } 
NF == 7 { 
      if (old_mark != $2) { counter = 0 } 
      old_mark = $2 
      $2 = substr($2, 1, 1) ++counter 
      printf("%s %3s %4s %5s %11s %7s %7s\n", $1, $2, $3, $4, $5, $6, $7); 
     } 

注意使用“列数中性的名字old_mark的。如果行9999包含CT和行万还含有CT,则映射必须是连续的(C1,C2)等,你可以使用:

NF < 7 { print; next } 
NF == 8 && $3 != "CT" && $3 != "F" && $3 != "HC" { print; next } 
NF == 7 && $2 != "CT" && $2 != "F" && $2 != "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", $1, $2, $3, $4, $5, $6, $7); 
    else 
     printf("%s %4s %3s %4s %5s %11s %7s %7s\n", $1, $2, $3, $4, $5, $6, $7, $8); 
} 

有可能是使用一个printf()呼叫的方式,但我怀疑是否值得努力。

+0

谢谢,但仍然存在问题。它停在9999行。有什么事吗? – Grego

+0

'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˚F103 1112 8.650 23.804 27.749 HETATM10004˚F103 1112 8.209 24.855 29.654 HETATM10005 F 103 1112 8.996 22.779 29.679' – Grego

+0

我发现我的问题! 'NF <3 {print;下一个} $ 2!=“CT”&& $ 2!=“F”&& $ 2!=“HC”{print;下一个} {如果(old_col2!= $ 2){计数器= 0} old_col2 = $ 16 $ 2 = SUBSTR($ 2,1,1)++计数器 的printf(“%S%3S%4S%5S%11S% 7s%7s \ n“,$ 1,$ 2,$ 3,$ 4,$ 5,$ 6,$ 7); }' – Grego

0

这里有一个while read循环来解决这个问题的一种方式,grepsed

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 

然后,您可以管到另一个文件或标准输出!

+0

所有的echo命令都应该使用'echo'$ line“'来保存空格(第一个不重要,其他两个可能很重要)。当每行输入至少有一个命令可以通过单个命令完成整个过程时,看起来很麻烦。 –

+0

这里的空间很好。我只是回应一些东西,而不是将它存储到变量或迭代任何东西。 – lxe

+0

虽然整个'if echo | grep -q'可以用'case'语句更好地表达。 – tripleee