0

抱歉这个冗长的问题,它归结为一个非常简单的问题。
假设有 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,而第二个仅包含组 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 文件,我想输出一个 .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

你会在日志文件中有明确的零或负数吗?我会假设不是。

你的第二个脚本的第一行没有做你想要的:

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

这分配"a"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

这是我对这个问题的看法。像这样运行:

./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 回答
1

对于每个 .log 文件,我想输出一个 .mean 文件,在第一列中列出整个组(广告)范围,并在第二列中列出相应的平均值或空格,具体取决于此类别是否存在于 .日志文件。

不是纯粹的 awk 解决方案,但您可以使用它获得所有组。

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

计算平均值后,您可以加入组文件。假设您的第二个输入文件的方法看起来像这个临时的中间文件。(我称之为 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 回答
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 回答