Как сопоставить имя столбца и узнать положение столбца в awk? - PullRequest
1 голос
/ 22 августа 2011

Я пытаюсь проанализировать некоторые CSV-файлы с помощью awk. Я новичок в сценариях оболочки и 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 (вместо того, чтобы явно указывать $ 2 или $ 3 при использовании awk).

Я гуглял по этому поводу и видел на разных форумах, но ни один из них, похоже, не работает. Может кто-нибудь сказать мне, как это сделать? Это было бы очень полезно!

Спасибо заранее !!

Ответы [ 2 ]

5 голосов
/ 22 августа 2011

Этот скрипт awk должен дать вам все, что вы хотите.

Сначала оценивается, какой столбец вас интересует, используя имя, переданное в качестве переменной COLM, и проверяя первую строку. Он преобразует это в индекс (он остается по умолчанию 0, если не может найти столбец).

Затем он в основном проходит через все остальные строки в вашем входном файле. Во всех этих других строках (при условии, что вы указали правильный столбец) обновляются счетчик, сумма, минимум и максимум как для общих данных, так и для каждого отдельного имени функции.

Первый хранится в count, sum, min и max. Последние хранятся в ассоциативных массивах с похожими именами (с добавлением _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
2 голосов
/ 22 августа 2011

Если я правильно понимаю требования, вам нужно среднее значение столбца и вы хотите указать столбец по имени.

Попробуйте следующий скрипт (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

EDIT:

Переписано для группировки по имени функции (предполагается, что это первое поле)

EDIT2:

Переписано, чтобы позволить дополнительному параметру фильтровать по имени функции (предполагается, что это первое поле)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...