次の例のような大きなログファイルのどこかにテーブルがあります。
_----------------------------
CARTESIAN COORDINATES (A.U.)
----------------------------
NO LB ZA FRAG MASS X Y Z
0 C 6.0000 0 12.011 -8.817666638854597 -4.911814574090662 58.264165798697491
1 C 6.0000 0 12.011 -7.879568488830738 -4.388761616508626 55.950914108733443
2 C 6.0000 0 12.011 -7.790669273242299 -4.339145245237274 60.527363919786708
3 C 6.0000 0 12.011 -7.070247938157430 -3.937287748509576 62.694740665963295
4 C 6.0000 0 12.011 -7.244178391763230 -4.034368638160922 53.748929835486599
5 H 1.0000 0 1.008 -6.427462410780078 -3.581016558829315 64.562423911622218
6 H 1.0000 0 1.008 -6.674286700050606 -3.718319003596096 51.850593400164620
--------------------------------
INTERNAL COORDINATES (ANGSTROEM)
--------------------------------
_
awk
にCARTESIAN COORDINATES (A.U.)
を見つけ、_NO LB
_を見つけてから、_-----
_の前の空白に達するまで各行の2番目の変数の読み取りを開始するように指示したい。
したがって、すべての要素(炭素(C
)酸素(O
)水素(H
))C
のH
と...次に、C
のH
の数を取得します。
この場合、_C5H2
_のような変数を作成しますが、最終的には_C3OH4
_のようなものになるかもしれません。
_awk '
/CARTESIAN COORDINATES (A.U.)/ {fcart=1}
fcart &&
/ NO LB/ {scart=1}
/---------------------------/{exit}
' OFS="\t" "$FILENAME"
_
このawk
を使用します。
_awk '/CARTESIAN COORDINATES \(A.U.\)/{a=1;next} a==1&&/NO LB/{b=1;next} $0==""{exit}
a==1&&b==1{c[$2]++} END{for(i in c){printf "%s%s", i,c[i]}}' file
_
/CARTESIAN COORDINATES \(A.U.\)/{a=1;next}
:このブロックはCARTESIAN COORDINATES (A.U.)
を検索し、変数a
を_1
_に設定し、next
は次の行にジャンプすることを意味しますその行で処理を再開します。a==1&&/NO LB/{b=1;next}
_は、a
が_1
_であるかどうか、および2番目の文字列_NO LB
_が行のどこかにあるかどうかを確認します。変数b
を設定し、next
行をロードします。$0==""{exit}
_:行が空の場合、処理を終了します(_END{}
_ブロックにジャンプします)。a==1&&b==1{c[$2]++}
_:両方の一致が見つかった場合(a
およびb
equal _1
_)c
という配列をインデックス_$2
_(フィールド2)。これにより、2番目のフィールドの各値の出現回数がカウントされます。END{...}
_:これは、ファイル処理が完了すると実行されます(配列がいっぱいになります)。for(i in c)
配列内の各要素を介して実行...printf "%s%s", i,c[i]
_:...インデックスと値を出力します。出力(サンプルファイルを使用):
_C5H2
_
さらに別のawkバージョン:
_awk '/NO.*[[:blank:]]LB/,/INTERNAL COORDINATES/ {
if($1~/[0-9]/){count[$2]++;}}
END {for(i in count){printf "%s%s",i,count[i]}print ""} ' file
_
これは、Sergの答えとChaosの答えの一種です。 _NO.*[[:blank:]]LB
_と_INTERNAL COORDINATES
_に一致する行間でのみ実行されます。 count
配列は、最初のフィールドが数値である行でのみカウントします。
ファイルが、連続するデータブロックが空の行で区切られている場所とまったく同じである場合、段落を行として扱うPerlの「段落モード」を使用できます。
_Perl -00ne 'next unless /CARTESIAN COORDINATES \(A\.U\.\)/;
$count{$_}++ for (/\s+\d+\s+(\w+)\s/g);
print "$_$count{$_}" for keys(%count)' file
_
-00
_:段落モードをオンにします。next unless /CARTESIAN COORDINATES \(A\.U\.\)/;
が一致しない場合、この段落をスキップしますCARTESIAN COORDINATES (A.U.)
;$count{$_}++ for (/\n\s+\d+\s+(\w+)\s/g)
:正規表現は、1つ以上の空白文字(_\s+
_)に続いて1つ以上の数字(_\d+
_)、1つ以上の空白文字、さらに1つ以上を探しますワード文字(_\w+
_)の後に空白文字が続きます。これにより、すべての要素が識別されます。 _%count
_はハッシュ、連想配列です。キーがあり、各キーは値に関連付けられています。 _$count{$_}++ for ...
_は、上記の正規表現の一致のそれぞれをそのハッシュのキーとして保存し、検出されるたびに値を1ずつ増やします。結果は、要素とそれぞれが見つかった回数を格納するハッシュです。print "$_$count{$_}" for keys(%count)
:各要素(ハッシュ_%count
_のキー)について、要素と見つかった回数を出力します。サンプルファイルで実行すると、次の結果が返されます。
_$ Perl -00ne 'next unless /CARTESIAN COORDINATES \(A\.U\.\)/;
$count{$_}++ for (/\s+\d+\s+(\w+)\s/g);
print "$_$count{$_}" for keys(%count)' file
C5H2$
_
ただし、最終的な改行はないため、次のように追加できます。
_$ Perl -00ne 'next unless /CARTESIAN COORDINATES \(A\.U\.\)/;
$count{$_}++ for (/\s+\d+\s+(\w+)\s/g);
print "$_$count{$_}" for keys(%count); print "\n"' file
C5H2
_
カオスの答えは、あなたが望むものを達成するために非常にうまく機能します。念のため、より簡単な代替手段を示します。
awk 'BEGIN{}
$2 ~ /^C$/ { countC++; } $2 ~ /^H$/ { countH++ }
END { print "C",countC,"H",countH; }' OFS="" file
出力C5H2
。
これはやや単純なコードです。
awk '/NO.*[[:blank:]]LB/,/INTERNAL COORDINATES/ { if ( $2 == "C") counterC++; if ($2 == "H") counterH++ } END {print "C"counterC"H"counterH} ' coordinates.txt
サンプル出力:
$ awk '/NO.*[[:blank:]]LB/,/INTERNAL COORDINATES/ { if ( $2 == "C") counterC++; if ($2 == "H") counterH++ } END {print "C"c>
C5H2