Bash - 在许多 .txt 文件中查找变量并计算统计信息
Bash - Find variable in many .txt files and calculate statistics
我的文件夹中有很多 .txt 文件。它们充满了统计数据,并且有一个代表这些统计数据所涉及的实验的名称。
exp_1_try_1.txt
exp_1_try_2.txt
exp_1_try_3.txt
exp_2_try_1.txt
exp_2_try_2.txt
exp_other.txt
在这些文件中,我需要找到具有特定名称的变量的值,并使用它们来计算一些统计数据:min、max、avg、std dev 和 median。
变量为十进制值加点“.”用作小数分隔符。没有科学记数法,尽管也可以很好地处理它。
#in file exp_1_try_1.txt
var1=30.523
var2=0.6
#in file exp_1_try_2.txt
var1=78.98
var2=0.4
#in file exp_1_try_3.txt
var1=78.100
var2=1.1
为了做到这一点,我使用了 bash。这是我在 bash 技能生锈之前制作的旧脚本。它计算整数值的平均值。
#!/bin/bash
folder=
varName="nHops"
cd "$folder"
grep -r -n -i --include="*_out.txt" "$varName" . | sed -E 's/(.+'"$varName"'=([0-9]+))|.*//' | awk '{count1+=; count2+=+1}END{print "avg hops:",count1/NR; print "avg path length:",count2/NR}' RS="\n"
我想将此脚本修改为:
- 支持查找可变长度的十进制值
- 计算更多统计数据
特别是 std dev 和 median 可能需要特别注意。
更新:这是我尝试仅使用 UNIX 工具解决问题的尝试,部分灵感来自 by this answer。它工作正常,除了它不计算标准偏差。所选答案使用 Perl 并且可能更快。
#!/bin/bash
folder=
varName="var1"
cd "$folder"
grep -r -n -i --include="exp_1_run_*" "$varName" . | sed -E 's/(.+'"$varName"'=([0-9]+(\.[0-9]*)?))//' | sort -n | awk '
BEGIN {
count = 0;
sum = 0;
}
{
a[count++] = ;
sum += ;
}
END {
avg = sum / count;
if( (count % 2) == 1 ) {
median = a[ int(count/2) ];
} else {
median = ( a[count/2] + a[count/2-1] ) / 2;
}
OFS="\t";
OFMT="%.6f";
print avg, median, a[0], a[count-1];
}
'
要仅提取值,请使用 -o
和 -P
grep 选项:
grep -rioPh --include="*_out.txt" "(?<=${varName}=)[\d.]+" .
它会寻找像 nHops=1.234
这样的模式,然后打印出 1.234
鉴于您的示例数据:
$ var="var1"
$ grep -oPh "(?<=$var=)[\d.]+" exp_1_try_{1,2,3}.txt
30.523
78.98
78.100
要输出一些统计数据,您应该能够将这些数字传送到您最喜欢的统计程序中。这是一个例子:
grep -oPh "(?<=$var=)[\d.]+" f? |
perl -MStatistics::Basic=:all -le '
@data = <>;
print "mean: ", mean(@data);
print "median: ", median(@data);
print "stddev: ", stddev(@data)
'
mean: 62.53
median: 78.1
stddev: 22.64
当然,因为这是 perl,我们根本不需要 grep 或 sed:
perl -MStatistics::Basic=:all -MList::Util=min,max -lne '
/'"$var"'\s*=\s*(\d+\.?\d*)/ and push @data,
} END {
print "mean: ", mean(@data);
print "median: ", median(@data);
print "stddev: ", stddev(@data);
print "min: ", min(@data);
print "max: ", max(@data);
' exp_1_try_*
mean: 62.53
median: 78.1
stddev: 22.64
min: 30.523
max: 78.98
我的文件夹中有很多 .txt 文件。它们充满了统计数据,并且有一个代表这些统计数据所涉及的实验的名称。
exp_1_try_1.txt
exp_1_try_2.txt
exp_1_try_3.txt
exp_2_try_1.txt
exp_2_try_2.txt
exp_other.txt
在这些文件中,我需要找到具有特定名称的变量的值,并使用它们来计算一些统计数据:min、max、avg、std dev 和 median。
变量为十进制值加点“.”用作小数分隔符。没有科学记数法,尽管也可以很好地处理它。
#in file exp_1_try_1.txt
var1=30.523
var2=0.6
#in file exp_1_try_2.txt
var1=78.98
var2=0.4
#in file exp_1_try_3.txt
var1=78.100
var2=1.1
为了做到这一点,我使用了 bash。这是我在 bash 技能生锈之前制作的旧脚本。它计算整数值的平均值。
#!/bin/bash
folder=
varName="nHops"
cd "$folder"
grep -r -n -i --include="*_out.txt" "$varName" . | sed -E 's/(.+'"$varName"'=([0-9]+))|.*//' | awk '{count1+=; count2+=+1}END{print "avg hops:",count1/NR; print "avg path length:",count2/NR}' RS="\n"
我想将此脚本修改为:
- 支持查找可变长度的十进制值
- 计算更多统计数据
特别是 std dev 和 median 可能需要特别注意。
更新:这是我尝试仅使用 UNIX 工具解决问题的尝试,部分灵感来自 by this answer。它工作正常,除了它不计算标准偏差。所选答案使用 Perl 并且可能更快。
#!/bin/bash
folder=
varName="var1"
cd "$folder"
grep -r -n -i --include="exp_1_run_*" "$varName" . | sed -E 's/(.+'"$varName"'=([0-9]+(\.[0-9]*)?))//' | sort -n | awk '
BEGIN {
count = 0;
sum = 0;
}
{
a[count++] = ;
sum += ;
}
END {
avg = sum / count;
if( (count % 2) == 1 ) {
median = a[ int(count/2) ];
} else {
median = ( a[count/2] + a[count/2-1] ) / 2;
}
OFS="\t";
OFMT="%.6f";
print avg, median, a[0], a[count-1];
}
'
要仅提取值,请使用 -o
和 -P
grep 选项:
grep -rioPh --include="*_out.txt" "(?<=${varName}=)[\d.]+" .
它会寻找像 nHops=1.234
这样的模式,然后打印出 1.234
鉴于您的示例数据:
$ var="var1"
$ grep -oPh "(?<=$var=)[\d.]+" exp_1_try_{1,2,3}.txt
30.523
78.98
78.100
要输出一些统计数据,您应该能够将这些数字传送到您最喜欢的统计程序中。这是一个例子:
grep -oPh "(?<=$var=)[\d.]+" f? |
perl -MStatistics::Basic=:all -le '
@data = <>;
print "mean: ", mean(@data);
print "median: ", median(@data);
print "stddev: ", stddev(@data)
'
mean: 62.53
median: 78.1
stddev: 22.64
当然,因为这是 perl,我们根本不需要 grep 或 sed:
perl -MStatistics::Basic=:all -MList::Util=min,max -lne '
/'"$var"'\s*=\s*(\d+\.?\d*)/ and push @data,
} END {
print "mean: ", mean(@data);
print "median: ", median(@data);
print "stddev: ", stddev(@data);
print "min: ", min(@data);
print "max: ", max(@data);
' exp_1_try_*
mean: 62.53
median: 78.1
stddev: 22.64
min: 30.523
max: 78.98