awk:计算不同文件中数据的平均值
awk: compute mean values for the data in distinct files
我正在使用 bash + awk 从目录中的日志文件中提取一些信息,并将摘要保存在单独的文件中。
在每个日志文件的底部,有一个 table 像:
mode | affinity | dist from best mode
| (kcal/mol) | rmsd l.b.| rmsd u.b.
-----+------------+----------+----------
1 -6.961 0 0
2 -6.797 2.908 4.673
3 -6.639 27.93 30.19
4 -6.204 2.949 6.422
5 -6.111 24.92 28.55
6 -6.058 2.836 7.608
7 -5.986 6.448 10.53
8 -5.95 19.32 23.99
9 -5.927 27.63 30.04
10 -5.916 27.17 31.29
11 -5.895 25.88 30.23
12 -5.835 26.24 30.36
由此我需要关注第二列中的(负)值。值得注意的是,我需要从第二列(从 -6.961 到 -5.916)中获取 10 个第一个值并计算它的平均值并将平均值与日志名称一起保存为新 ranking.log 中的一个字符串
所以对于 5 个处理过的日志,它应该是这样的:
# ranking_${output}.log
log_name1 -X.XXX
log_name2 -X.XXX
log_name3 -X.XXX
log_name4 -X.XXX
log_name5 -X.XXX
其中 -X.XXX 是为每个日志计算的前 10 个位置的平均值。
这是我在 bash 函数中集成的 awk 代码,它从每个日志中提取第一个值(示例 table 中的 -6.961 )(没有均值计算)。
# take only the first line (lowest dG) from each log
take_the_first_value () {
awk '=="1"{sub(/.*\//,"",FILENAME); sub(/\.log/,"",FILENAME); printf("%s: %s\n", FILENAME, )}' "${results}"/*.log > "${results}"/ranking.csv
}
我可以修改 AWK 部分以添加 MEAN 值的计算,而不是始终采用位于 table 的第一行的值吗?
我建议使用 GNU awk
:
awk -v num=10 'BEGINFILE{ c=sum=0 }
~/^[0-9]+$/ && NF==4{
c++; sum=sum+;
if(c==num){
sub(/.*\//, "", FILENAME);
print FILENAME, sum/num
}
}' "${results}"/*.log >> "${results}"/ranking.csv
我使用 ~/^[0-9]+$/ && NF==4
来识别正确的行。
这为您提供了平均值。用于查找第一个值的模式是行 ^---+---
后跟下一行的第一个字段中的 [:digit:]
。对于每个日志文件做
$ awk '~/[[:digit:]]/ && set==1{ x+=; i++;
gsub(/\/*.*\//,"", FILENAME);
if(i==10){ set=0; print FILENAME, x/i; i=0; x=0 } }
/^\-+\+\-+/{ set=1 }' "${results}"/*.log > "${results}"/ranking.csv
对于 ENDFILE 使用 GNU awk:
$ cat tst.sh
#!/usr/bin/env bash
awk '
(+0) < 0 {
sum +=
if ( ++cnt == 10 ) {
nextfile
}
}
ENDFILE {
print FILENAME, (cnt ? sum/cnt : 0)
cnt = sum = 0
}
' "${@:--}"
$ ./tst.sh file
file -6.2549
请注意,即使您的输入文件末尾少于 10 行(包括空文件),上述方法也能正常工作。
我正在使用 bash + awk 从目录中的日志文件中提取一些信息,并将摘要保存在单独的文件中。 在每个日志文件的底部,有一个 table 像:
mode | affinity | dist from best mode
| (kcal/mol) | rmsd l.b.| rmsd u.b.
-----+------------+----------+----------
1 -6.961 0 0
2 -6.797 2.908 4.673
3 -6.639 27.93 30.19
4 -6.204 2.949 6.422
5 -6.111 24.92 28.55
6 -6.058 2.836 7.608
7 -5.986 6.448 10.53
8 -5.95 19.32 23.99
9 -5.927 27.63 30.04
10 -5.916 27.17 31.29
11 -5.895 25.88 30.23
12 -5.835 26.24 30.36
由此我需要关注第二列中的(负)值。值得注意的是,我需要从第二列(从 -6.961 到 -5.916)中获取 10 个第一个值并计算它的平均值并将平均值与日志名称一起保存为新 ranking.log 中的一个字符串 所以对于 5 个处理过的日志,它应该是这样的:
# ranking_${output}.log
log_name1 -X.XXX
log_name2 -X.XXX
log_name3 -X.XXX
log_name4 -X.XXX
log_name5 -X.XXX
其中 -X.XXX 是为每个日志计算的前 10 个位置的平均值。
这是我在 bash 函数中集成的 awk 代码,它从每个日志中提取第一个值(示例 table 中的 -6.961 )(没有均值计算)。
# take only the first line (lowest dG) from each log
take_the_first_value () {
awk '=="1"{sub(/.*\//,"",FILENAME); sub(/\.log/,"",FILENAME); printf("%s: %s\n", FILENAME, )}' "${results}"/*.log > "${results}"/ranking.csv
}
我可以修改 AWK 部分以添加 MEAN 值的计算,而不是始终采用位于 table 的第一行的值吗?
我建议使用 GNU awk
:
awk -v num=10 'BEGINFILE{ c=sum=0 }
~/^[0-9]+$/ && NF==4{
c++; sum=sum+;
if(c==num){
sub(/.*\//, "", FILENAME);
print FILENAME, sum/num
}
}' "${results}"/*.log >> "${results}"/ranking.csv
我使用 ~/^[0-9]+$/ && NF==4
来识别正确的行。
这为您提供了平均值。用于查找第一个值的模式是行 ^---+---
后跟下一行的第一个字段中的 [:digit:]
。对于每个日志文件做
$ awk '~/[[:digit:]]/ && set==1{ x+=; i++;
gsub(/\/*.*\//,"", FILENAME);
if(i==10){ set=0; print FILENAME, x/i; i=0; x=0 } }
/^\-+\+\-+/{ set=1 }' "${results}"/*.log > "${results}"/ranking.csv
对于 ENDFILE 使用 GNU awk:
$ cat tst.sh
#!/usr/bin/env bash
awk '
(+0) < 0 {
sum +=
if ( ++cnt == 10 ) {
nextfile
}
}
ENDFILE {
print FILENAME, (cnt ? sum/cnt : 0)
cnt = sum = 0
}
' "${@:--}"
$ ./tst.sh file
file -6.2549
请注意,即使您的输入文件末尾少于 10 行(包括空文件),上述方法也能正常工作。