正则表达式在多个文件中的特定字符串后 grep 编号并返回平均值

正则表达式在多个文件中的特定字符串后 grep 编号并返回平均值

我想返回多个文件中特定字符串后所有数字的平均值,即

我们有 10 个文件 (file1.txt,...,file10.txt)。每个文件都包含其他内容

Test1: Avg. length 24.01000, time: 0.579
Test2: Avg. length 22.02000, time: 0.879

具有不同的数字。

如果我们有 10 个文件,它可能看起来像

文件1.txt

Test1: Avg. length 24.01000, time: 0.679
Test2: Avg. length 22.01000, time: 0.479

文件2.txt

Test1: Avg. length 27.01000, time: 0.279
Test2: Avg. length 24.01000, time: 0.779

……

文件10.txt

我想要的输出是所有文件中 Test1 和 Test2 的长度和时间的平均值:

Mean Test1: Avg. length (file1_Test1_length+...+file10_Test1_lenght)/10, time (file1_Test1_time+...+file_10_Test1_time)/10
Mean Test2: Avg. length (file1_Test2_length+...+file10_Test2_lenght)/10, time (file1_Test2_time+...+file_10_Test2_time)/10

为了 grep Test1 的完整输出,我执行:

egrep -rh 'Test1: Avg. length.*' /home/timo/Documents

我不知道如何只 grep 数字。我试过

egrep -rhP '(?<=length )\d+' /home/timo/Documents

但我收到一个错误

grep: conflicting matchers specified

如果有人能帮助我,我将非常感激!

答案1

以下awk解决方案应该有效:

awk -F'[ ,:]+' '$1~/^Test[12]/{l[$1]+=$4; t[$1]+=$6; n[$1]++;}
                END{if (n["Test1"]) {for (tst in l) printf("Mean %s: Avg. length %f, time: %f\n",tst,l[tst]/n[tst], t[tst]/n[tst]);} else {print "No input found"}}' file*.txt

这将解析输入文件中以Test1or开头的行Test2以及总和字段 4 和 6(分别为“长度”和“时间”)。另外,它还会增加数据计数器n。最后,它将打印平均值(如果找到任何数据)或错误消息。

如果您确定至少存在一个文件,您可以将其简化为

awk -F'[ ,:]+' '$1~/^Test[12]/{l[$1]+=$4; t[$1]+=$6; n[$1]++;}
                END{for (tst in l) printf("Mean %s: Avg. length %f, time: %f\n",tst,l[tst]/n[tst], t[tst]/n[tst]);}' file*.txt

由于所有文件似乎都位于单独的子文件夹中,因此该方法取决于您的 shell。在最简单的情况下,你可以尝试

awk -F'[ ,:]+' ' ... ' subdir*/file*.txt

答案2

使用 GNU datamash

$ grep '^Test.*Avg\. length.*time:' file*.txt | tr -d ',' | LC_ALL=C datamash -W -s -g 1 mean 4,6
Test1:  25.51   0.479
Test2:  23.01   0.629

这首先提取您使用显示的行grep。我通过匹配Test行开头的文本,然后是字符串Avg. lengthtime:该行的其他位置来实现此目的。您可能想修改这个表达式(我不知道它是否唯一匹配仅有的我们感兴趣的行)。

然后我从数据中删除所有逗号,因为它们扰乱了数字的解释。我这样做是用tr.

grep+位也可以用astr来完成sed

sed '/^Test.*Avg\. length.*time:/!d; s/,//g' file*.txt

然后我使用 GNUdatamash计算每个测试的平均长度和时间。我首先告诉datamash使用 空格作为分隔符-W。对-s数据进行排序,因为它来自grep+ tr(或sed),以便有效地对数据进行全局分组。

分组是通过将每行上的标签-g 1定义TestN:为分组键来完成的。然后,对于每个这样的组,计算第 4 个和第 6 个空格分隔列的平均值,其中mean 4,6.

我将 for 的区域设置设置为C(POSIX 区域设置)datamash,因为该实用程序可能希望十进制数字使用逗号而不是点作为小数点。

您想稍微装饰一下输出吗,可以使用以下命令awk

sed '/^Test.*Avg\. length.*time:/!d; s/,//g' file*.txt |
LC_ALL=C datamash -W -s -g 1 mean 4,6 |
awk '{ printf "%s Avg. length: %s time: %s\n", $1,$2,$3 }'

这可能会输出类似的内容

Test1: Avg. length: 25.51 time: 0.479
Test2: Avg. length: 23.01 time: 0.629

相关内容