在awk中不存在的索引上的数组

时间:2012-11-25 11:16:31

标签: awk

对于冗长的问题感到抱歉,这归结为一个非常简单的问题 假设有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;

Howerver,由于上述原因,生成的.mean文件的长度因文件而异。对于每个.log文件,我想输出一个.mean文件,列出第一列中的整个组(ad)和相应的平均值或第二列中的空白空间,具体取决于该类别是否存在于。日志文件。我已经尝试了以下代码(为简洁而没有$ 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 个答案:

答案 0 :(得分: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;

答案 1 :(得分:1)

  

对于每个.log文件,我想输出一个列出整个文件的.mean文件   第一列中的组(a-d)范围和相应的平均值   第二列中的值或空格取决于是否这样   类别存在于.log文件中。

不仅仅是一个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

答案 2 :(得分: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

答案 3 :(得分: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]}'

很容易将其推入文件 -