Считайте таблицу после определенной строки и считайте occrences с awk

У меня есть таблица где-нибудь в большом файле журнала, который похож на этот пример:

----------------------------
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"
5
задан 29 September 2015 в 13:06

4 ответа

Используйте это 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
6
ответ дан 23 November 2019 в 08:43

Вот несколько более простой код:

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
2
ответ дан 23 November 2019 в 08:43

ответ хаоса работает очень хорошо для выполнения то, что Вы хотите. Вот более простая альтернатива на всякий случай,

awk 'BEGIN{}
$2 ~ /^C$/ { countC++; } $2 ~ /^H$/ { countH++ }
END { print "C",countC,"H",countH; }' OFS="" file

Дает вывод C5H2.

2
ответ дан 23 November 2019 в 08:43

Еще одна 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
4
ответ дан 23 November 2019 в 08:43

Другие вопросы по тегам:

Похожие вопросы: