Text-Processing

在多個文件中的特定字元串之後 grep 數字並返回平均值的正則表達式

  • February 16, 2021

我想在多個文件中的特定字元串之後返回所有數字的平均值,即

我們有 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

如果有人可以幫助我,我將非常感激!

使用 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+tr位也可以用sedas

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.

我將語言環境設置為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

以下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

這將解析輸入文件的起始行Test1Test2和總和欄位 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

引用自:https://unix.stackexchange.com/questions/634724