0

冗長な質問で申し訳ありませんが、それは非常に単純な問題に要約されます。
文字列の1つの列(グループを表す)と整数の1つ(これらのグループ内のインスタンスの値を表す)をそれぞれ含むn個のテキストファイルがあると仮定します。

  # filename xxyz.log
  a 5  
  a 6  
  b 10  
  b 15  
  c 101  
  c 100  

  #filename xyzz.log
  a 3  
  a 5  
  c 116  
  c 128

特定のファイル内の両方の列の長さは常に同じですが、ファイル間で異なることに注意してください。さらに、すべてのファイルに同じ範囲のグループが含まれているわけではありません(最初のファイルにはグループa、b、cが含まれ、2番目のファイルにはグループaとcのみが含まれます)。awkでは、各ファイル内の列1の各文字列の列2の平均を個別に計算し、次のコードで結果を出力できます。

  NAMES=$(ls|grep .log|awk -F'.' '{print $1}');

  for q in $NAMES;
  do
    gawk -F' ' -v y=$q 'BEGIN {print "param", y}
    {sum1[$1] += $2; N[$1]++}
    END     {for (key in sum1) {
                       avg1 = sum1[key] / N[key];
                       printf "%s %f\n", key, avg1;
                   } }' $q.log | sort > $q.mean;
  done;

ただし、上記の理由により、結果の.meanファイルの長さはファイル間で異なります。.logファイルごとに、最初の列にグループ(ad)の全範囲をリストし、2番目の列に対応する平均値または空のスペースをリストする.meanファイルを出力します。これは、このカテゴリがに存在するかどうかによって異なります。ログファイル。私は次のコードを試しました(簡潔にするために$ NAMESなしで与えられています):

  awk 'BEGIN{arr[a]="a"; arr[b]="b"; arr[c]="c"; arr[d]="d"} 
  {sum[$1] += $2; N[$1]++} 
  END {for (i in arr) {
  if (i in sum) {
    avg = sum[i] / N[i]; 
    printf "%s %f\n" i, avg;} 
  else {
    printf "%s %s\n" i, "";}
  }}' xxyz.log > xxyz.mean;

ただし、次のエラーが返されます。

awk: (FILENAME=myfile FNR=7) fatal: not enough arguments to satisfy format string
        `%s %s
'
            ^ ran out for this one

任意の提案をいただければ幸いです。

4

4 に答える 4

2

ログファイルに明示的なゼロまたは負の数があることはありますか?私はそうは思わないつもりです。

2番目のスクリプトの最初の行は、希望どおりに機能しません。

awk 'BEGIN{arr[a]="a"; arr[b]="b"; arr[c]="c"; arr[d]="d"} 

これは、 (以前に使用されていない変数であるため)、次に同じ要素(以前に使用されていない変数であるため)、次に、、"a"を割り当てます。明らかに、あなたが考えていたものではありません。この(テストされていない)コードは、4つのグループしかないことがわかっている限り、必要な仕事をするはずです。グループを事前に知らない場合は、より複雑なプログラムが必要です(実行できますが、より困難です)。arr[0]a"b"b"c""d"

awk 'BEGIN { sum["a"] = 0; sum["b"] = 0; sum["c"] = 0; sum["d"] = 0 } 
     { sum[$1] += $2; N[$1]++ } 
     END {   for (i in sum) {
                 if (N[i] == 0) N[i] = 1 # Divide by zero protection
                 avg = sum[i] / N[i]; 
                 printf "%s %f\n" i, avg;
             } 
         }' xxyz.log > xxyz.mean;

これにより、欠落しているグループの平均がゼロになります。必要に応じて、次のことができます。

awk 'BEGIN { sum["a"] = 0; sum["b"] = 0; sum["c"] = 0; sum["d"] = 0 } 
     { sum[$1] += $2; N[$1]++ } 
     END {   for (i in sum) {
                 if (N[i] == 0)
                     printf("%s\n", i;
                 else {
                     avg = sum[i] / N[i]; 
                     printf "%s %f\n" i, avg;
                 }
             } 
         }' xxyz.log > xxyz.mean;
于 2012-11-25T13:48:30.737 に答える
1

.logファイルごとに、最初の列にグループ(ad)の全範囲をリストし、2番目の列に対応する平均値または空のスペースをリストする.meanファイルを出力します。これは、このカテゴリがに存在するかどうかによって異なります。ログファイル。

純粋にawkソリューションではありませんが、これですべてのグループを取得できます。

awk '{print $1}' *.log | sort -u > groups

平均を計算した後、グループファイルに参加できます。2番目の入力ファイルの手段がこの一時的な中間ファイルのように見えるとしましょう。(私はそれをxyzz.tmpと呼びました。)

a 4
c 122

グループに参加し、グループファイルのすべての値を保持します。

$ join -a1 groups xyzz.tmp > xyzz.mean
$ cat xyzz.mean
a 4
b
c 122
于 2012-11-25T12:01:14.963 に答える
1

これが私の問題に対する見方です。次のように実行します:

./script.sh

内容script.sh

array=($(awk '!a[$1]++ { print $1 }' *.log))

readarray -t sorted < <(for i in "${array[@]}"; do echo "$i"; done | sort)

for i in *.log; do
    for j in "${sorted[@]}"; do
        awk -v var=$j '
            {
                sum[$1]+=$2
                cnt[$1]++
            }
            END {
                print var, (var in cnt ? sum[var]/cnt[var] : "")
            }
        ' "$i" >> "${i/.log/.main}"
    done
done

の結果grep . *.main

xxyz.main:a 5.5
xxyz.main:b 12.5
xxyz.main:c 100.5
xyzz.main:a 4
xyzz.main:b 
xyzz.main:c 122
于 2012-11-25T15:44:37.740 に答える
0

これが純粋なawkの答えです:

find . -maxdepth 1 -name "*.log" -print0 | 
  xargs -0 awk '{SUBSEP=" ";sum[FILENAME,$1]+=$2;cnt[FILENAME,$1]+=1;next}
  END{for(i in sum)print i, sum[i], cnt[i], sum[i]/cnt[i]}'

これをファイルにプッシュするのに十分簡単-

于 2012-11-25T13:16:20.407 に答える