如何匹配列名并找出awk中的列位置?

时间:2011-08-22 07:51:13

标签: shell unix awk

我正在尝试使用awk解析一些csv文件。我是shell脚本和awk的新手。 我正在处理的csv文件看起来像这样:

fnName,minAccessTime,maxAccessTime
getInfo,300,600
getStage,600,800
getStage,600,800
getInfo,250,620
getInfo,200,700
getStage,700,1000
getInfo,280,600

我需要找到不同功能的平均访问时间。

我一直在使用awk并且能够获得平均时间,只要指定了确切的列号,如 $ 2,$ 3 等。

但是我需要有一个通用脚本,如果我在命令参数中输入“minAccessTime”,我需要脚本来打印平均AccessTime(而不是在使用awk时显式指定$ 2或$ 3)。

我一直在谷歌上搜索,并在各种论坛上看到,但似乎没有一个工作。 谁能告诉我怎么做?这将是非常有帮助的!

提前致谢!!

2 个答案:

答案 0 :(得分:5)

这个awk脚本可以为您提供所需的一切。

首先使用作为COLM变量传入的名称并检查第一行来评估您感兴趣的列。它将其转换为索引(如果找不到列,则将其保留为默认值0。)

然后它基本上会遍历输入文件中的所有其他行。在所有这些其他行上(假设您已指定有效列),它会更新整体数据加上每个单独函数名称的计数,总和,最小值和最大值。

前者存储在countsumminmax中。后者存储在具有相似名称的关联数组中(附加_arr)。

然后,一旦读取了所有记录,END部分就会输出信息。

NR == 1 {
    for (i = 1; i <= NF; i++) {
        if ($i == COLM) {
            cidx = i;
        }
    }
}

NR > 1 {
    if (cidx > 0) {
        count++;
        sum += $cidx;
        if (count == 1) {
            min = $cidx;
            max = $cidx;
        } else {
            if ($cidx < min) { min = $cidx; }
            if ($cidx > max) { max = $cidx; }
        }

        count_arr[$1]++;
        sum_arr[$1] += $cidx;
        if (count_arr[$1] == 1) {
            min_arr[$1] = $cidx;
            max_arr[$1] = $cidx;
        } else {
            if ($cidx < min_arr[$1]) { min_arr[$1] = $cidx; }
            if ($cidx > max_arr[$1]) { max_arr[$1] = $cidx; }
        }
    }
}

END {
    if (cidx == 0) {
        print "Column '" COLM "' does not exist"
    } else {
        print "Overall:"
        print "   Total records = " count
        print "   Sum of column = " sum
        if (count > 0) {
            print "   Min of column = " min
            print "   Max of column = " max
            print "   Avg of column = " sum / count
        }
        for (task in count_arr) {
            print "Function " task ":"
            print "   Total records = " count_arr[task]
            print "   Sum of column = " sum_arr[task]
            print "   Min of column = " min_arr[task]
            print "   Max of column = " max_arr[task]
            print "   Avg of column = " sum_arr[task] / count_arr[task]
        }
    }
}

将该脚本存储到qq.awk并将您的示例数据放入qq.in,然后运行:

awk -F, -vCOLM=minAccessTime -f qq.awk qq.in

生成以下输出,我相对肯定会为您提供所需的所有可能信息:

Overall:
   Total records = 7
   Sum of column = 2930
   Min of column = 200
   Max of column = 700
   Avg of column = 418.571
Function getStage:
   Total records = 3
   Sum of column = 1900
   Min of column = 600
   Max of column = 700
   Avg of column = 633.333
Function getInfo:
   Total records = 4
   Sum of column = 1030
   Min of column = 200
   Max of column = 300
   Avg of column = 257.5

对于`maxAccessTime,你得到:

Overall:
   Total records = 7
   Sum of column = 5120
   Min of column = 600
   Max of column = 1000
   Avg of column = 731.429
Function getStage:
   Total records = 3
   Sum of column = 2600
   Min of column = 800
   Max of column = 1000
   Avg of column = 866.667
Function getInfo:
   Total records = 4
   Sum of column = 2520
   Min of column = 600
   Max of column = 700
   Avg of column = 630

而且,对于xyzzy(一个不存在的列),您会看到:

Column 'xyzzy' does not exist

答案 1 :(得分:2)

如果我正确理解了这些要求,您需要列的平均值,并且您希望按名称指定列。

尝试以下脚本(avg.awk):

BEGIN {
  FS=",";
}

NR == 1 {
  for (i=1; i <= NF; ++i) {
    if ($i == SELECTED_FIELD) {
      SELECTED_COL=i;
    }
  }
}

NR > 1 && $1 ~ SELECTED_FNAME {
  sum[$1] = sum[$1] + $SELECTED_COL;
  count[$1] = count[$1] + 1;
}

END {
  for (f in sum) {
    printf("Average %s for %s: %d\n", SELECTED_FIELD, f, sum[f] / count[f]);
  }
}

并像这样调用你的脚本

awk -v SELECTED_FIELD=minAccessTime -f avg.awk < data.csv

awk -v SELECTED_FIELD=maxAccessTime -f avg.awk < data.csv

awk -v SELECTED_FIELD=maxAccessTime -v SELECTED_FNAME=getInfo -f avg.awk < data.csv

编辑:

按功能名称重写为组(假设为第一个字段)

EDIT2:

重写以允许按功能名称(假设为第一个字段)过滤其他参数