複数のファイルの特定の文字列の後に数値を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

Test1の出力全体をgrepするには、次のようにします。

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。最後に、平均値(データが見つかった場合)またはエラーメッセージを印刷します。

少なくとも1つのファイルが存在すると確信している場合は、次のように単純化できます。

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

すべてのファイルが別々のサブフォルダーにあるように見えるため、方法はシェルによって異なります。最も簡単な場合は試してみてください。

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

まず、表示に使用する行を抽出しますgrepTest行の先頭にあるテキストを一致させてから、文字列と行の他の部分Avg. lengthtime:一致させてこれを行います。この式を修正したい場合があります(一意に一致するかどうかわかりません)。ただ私たちが興味のある行)。

その後、数値解釈を混乱させるので、データからすべてのカンマを削除しました。私はこれを使ってtr

grep+ビットは、次のように実行することもtrできます。sed

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

次に、GNUを使用してdatamash各テストの平均長さと時間を計算します。私は最初にdatamashスペースを区切り文字として使用するように言いました-W。 +(または)-sから来るようにデータをソートして、データをグローバルに効果的にグループ化します。greptrsed

グループ化は、各行のラベルをグループ化キーとして定義することによって-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

関連情報