У меня есть таблица где-то в большом файле журнала, который выглядит следующим образом:
----------------------------
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, затем начать чтение вторая переменная в каждой строке до тех пор, пока она не достигнет пробела до -----.
Итак, я буду читать все (элементы Carbon (C) Oxygen (O) Hydrogen (H )) C 's H' s и ... тогда я получаю, сколько C 's H.
У меня есть, и я могу сделать переменную типа [ f14] в этом случае может оказаться что-то вроде C3OH4, любых идей?
awk '
/CARTESIAN COORDINATES (A.U.)/ {fcart=1}
fcart &&
/ NO LB/ {scart=1}
/---------------------------/{exit}
' OFS="\t" "$FILENAME"
Еще одна 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
Это своего рода смесь между ответом Серга и Хаосом. Он будет работать только между строками, соответствующими NO.*[[:blank:]]LB и INTERNAL COORDINATES. Массив count учитывает только строки, первое поле которых является числом.
Если ваш файл точно так же, как вы показываете, где последовательные блоки данных разделены пустой строкой, вы можете использовать режим абзаца Perl, который обрабатывает абзацы как строки: [ ! d3]
perl -00ne 'next unless /CARTESIAN COORDINATES \(A\.U\.\)/;
$count{$_}++ for (/\s+\d+\s+(\w+)\s/g);
print "$_$count{$_}" for keys(%count)' file
Запустите файл вашего примера, это возвращает:
$ 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 '/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
Ответ хаоса очень хорошо работает, чтобы выполнить то, что вы хотите. Вот еще более простая альтернатива:
awk 'BEGIN{}
$2 ~ /^C$/ { countC++; } $2 ~ /^H$/ { countH++ }
END { print "C",countC,"H",countH; }' OFS="" file
Дает выход C5H2.