1

約 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 の 2 番目の 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
...

ありがとう

4

2 に答える 2

1

awkよりも簡単に使用できますが、本当にしたい場合は、でも使用できるsedことに疑いの余地はありません。sed

必要がある:

  • フィールド数が 1 (または 2 — 3 未満) の行を出力します。
  • 列が 3 つ以上ある場合は、列 3 の最後の値を追跡します。
  • 現在の列が CT、F、または HC のいずれかである場合:
    • 列 3 の最後の値が異なる場合は、入力列 3 を最初の文字に 1 を加えたものに置き換えます。出力した 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
}

そして、それをデータ ファイル (名前が付けられていませんが、名前が付けられ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);

これにより、間隔は保持されますが、一般的にコードの堅牢性が低下します。n inより短い文字列は右揃えになるという特性を利用します%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

10,000 レコードに到達するHETATMと、次の列と数値列が 1 つの列にマージされます。

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。行 9,999 に が含まれCT、行 10,000 にも が含まれている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);
}

1回の呼び出しを使用する方法があるかもしれませんがprintf()、努力する価値があるかどうかは疑問です.

于 2015-05-14T21:53:33.770 に答える
0

while readこれをループでgrep解決する 1 つの方法を次に示し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

その後、それを別のファイルまたは stdout にパイプできます。

于 2015-05-14T21:12:12.577 に答える