![正则表达式在多个文件中的特定字符串后 grep 编号并返回平均值](https://linux22.com/image/188163/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%9C%A8%E5%A4%9A%E4%B8%AA%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E7%89%B9%E5%AE%9A%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%90%8E%20grep%20%E7%BC%96%E5%8F%B7%E5%B9%B6%E8%BF%94%E5%9B%9E%E5%B9%B3%E5%9D%87%E5%80%BC.png)
我想返回多个文件中特定字符串后所有数字的平均值,即
我们有 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
这将解析输入文件中以Test1
or开头的行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. length
和time:
该行的其他位置来实现此目的。您可能想修改这个表达式(我不知道它是否唯一匹配仅有的我们感兴趣的行)。
然后我从数据中删除所有逗号,因为它们扰乱了数字的解释。我这样做是用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