У меня есть таблица где-нибудь в большом файле журнала, который похож на этот пример:
----------------------------
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
затем начинает читать вторую переменную в каждой строке, пока она не достигает пробела прежде -----
.
Так, я буду читать весь (Углерод элементов (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
и если вторая строка NO LB
найден где-нибудь в строке. Это устанавливает переменную b
и затем загрузки next
строка.$0==""{exit}
: Затем, если строка является пустым выходом обработка (это переходит к END{}
блок).a==1&&b==1{c[$2]++}
: Если оба соответствия найдены (a
и b
равный 1
) увеличьте названный массив c
с индексом $2
(поле 2). Это будет считать происшествия каждого значения во втором поле.END{...}
: Это будет работать, когда обработка файла будет сделана (массив заполнен). for(i in c)
выполненная канавка каждый элемент в массиве...printf "%s%s", i,c[i]
:... и распечатайте индекс и значение.Вывод (с Вашим файлом в качестве примера):
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
.
Еще одна 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)
: регулярное выражение ищет один или несколько пробельных символов (\s+
), сопровождаемый одной или несколькими цифрами (\d+
), один или несколько пробельных символов снова и затем один или несколько словесных символов (\w+
) сопровождаемый пробельным символом. Это должно определить все элементы. %count
хеш, ассоциативный массив. Это имеет ключи, и каждый ключ связан со значением. $count{$_}++ for ...
сохранит каждое из соответствий regex выше как ключ в том хеше и увеличит его значение к одному каждому разу, когда это найдено. Результатом является хеш, который хранит элементы и количество раз, которым каждый был найден.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