Поиск среднего значения выбранных элементов в столбце в bash

#bash #awk #bc

Вопрос:

У меня есть файл, содержащий координаты атомов в следующем формате

 A B C
1 2 1
some string
another line of string
  0.00  0.00  0.35
  0.33  0.99  0.37
  0.66  0.50  0.98
  0.66  0.00  0.38
 

A B и C-это названия различных атомов в системе

В следующей строке «1 2 1» указано количество атомов каждого типа, поэтому 1A, 2Bs и 1C.

Следующие строки с тремя столбцами поплавков дают декартовы координаты каждого атома, поэтому первая строка предназначена для A, вторая и третья строки для каждого из двух B, четвертая строка для C.

Я хочу найти среднее значение координат z двух атомов B, т. е. Среднее(0,37, 0,98). и заменить координату z атома C на это значение, т. е. Заменить 0,38 на Среднее(0,37, 0,98).

В реальной проблеме, с которой я столкнулся, есть несколько десятков файлов, каждый из которых содержит разное количество атомов A, B и C. поэтому мне нужно прочитать цифры в строке 2 и решить, с какими строками столбца 3 работать. Есть ли эффективный способ сделать это в bash, awk или что-то подобное?

Я знаю, что могу прочитать весь файл целиком и прочитать весь 3-й столбец в массив с помощью чего-то вроде следующего, а затем работать.

 #!/bin/bash

array_B=( $(cut -d ' ' -f3 file ) )
printf "%sn" "${array_B[2]}"
 

Но у этого есть проблемы, связанные с первыми 4 строками, а затем с проблемой идентификации соответствующих строк, соответствующих B. Есть какие-нибудь предложения?

Заранее спасибо Яцек


Связанный с этим вопрос:

Если я хочу изменить координату z атома A на среднее значение координаты z атома Bs, как мне структурировать код? Если мы используем AWK и позволим ему читать файл строка за строкой, среднее значение не вычисляется до тех пор, пока AWK не достигнет строк, касающихся атома B. Для атома А, который предшествует атому В, возникнет проблема. Я думаю, что тогда нам нужно позволить AWK просмотреть файл один раз, чтобы получить среднее значение, а затем еще раз, чтобы изменить значения третьего столбца для соответствующих строк. Однако я не знаю, как установить эту переменную. awk -v воля дает только заранее определенное значение.

Комментарии:

1. Если вы хотите изменить входные файлы, не делайте этого. Считайте файлы неизменяемыми. Если вам нужно изменить данные, запишите новые данные в совершенно другое дерево каталогов. Диск стоит дешево. Временное наличие избыточных данных в вашей файловой системе не имеет большого значения. Восстановление поврежденных данных стоит дорого; это займет много времени и вызовет большое разочарование.

2. @WilliamPursell Я не перезаписываю исходный файл, просто пытаюсь отредактировать файл в соответствии с тем, что я описал, и сохранить его в качестве входных данных для другого расчета. Однако я не могу понять, как заставить awk работать так, как я описал.

Ответ №1:

С помощью awk :

 awk '
  BEGIN { start_b = end_b = 4; total = 0 } # Initial dummy values
  FNR == 2 { # Calculate line numbers for B and C atoms
             num_b=$2; start_b=4 $1; end_b=start_b num_b
           }
  FNR <= start_b { print }
  FNR > start_b amp;amp; FNR <= end_b { total  = $3; print } # Sum up b z-coords
  FNR > end_b { printf "  %.2f  %.2f  %.2fn", $1, $2, total / num_b } # Replace the C z-coords with average of b
  ' file
 

Комментарии:

1. У меня есть вопрос. Если я хочу изменить координату z A на среднее значение координат z двух атомов B, т. Е. Среднее значение(0,37, 0,98), как я должен структурировать awk? Прямо сейчас, поскольку total обновляется только при чтении awk в строку, содержащую информацию B, при изменении координаты z для A total по-прежнему использует значение по умолчанию, а не значение для чтения.