AWK, подсчитайте частоту имен машин в нескольких файлах журнала

У меня файлы журналов не менее 100Гб. Структура каталогов файла журнала похожа на эту :

drwxrwxr-x 2 griyn griyn 4096 Jul  2 14:33 lcdc-0615-00.log
drwxrwxr-x 2 griyn griyn 4096 Jun 29 14:22 lcdc-0615-01.log
drwxrwxr-x 2 griyn griyn 4096 Jun 28 21:25 lcdc-0615-02.log
drwxrwxr-x 2 griyn griyn 4096 Jun 28 21:25 lcdc-0615-03.log
drwxrwxr-x 2 griyn griyn 4096 Jun 28 21:25 lcdc-0615-04.log
drwxrwxr-x 2 griyn griyn 4096 Jun 28 21:25 lcdc-0615-05.log
drwxrwxr-x 2 griyn griyn 4096 Jun 28 21:25 lcdc-0615-06.log

И в каждом каталоге

[griyn@cp01-vm-griyn test_data]$ cd lcdc-0615-00.log/
[griyn@cp01-vm-griyn lcdc-0615-00.log]$ ll
total 361216
-rw-rw-r-- 1 griyn griyn 184936785 Jun 28 21:19 yq01-spi-mx0.yq01
-rw-rw-r-- 1 griyn griyn 184936680 Jun 28 21:20 yq01-spi-mx22.yq01

содержимое файла журнала здесь,

  1 peer_addr[yq01-spi-mx38:29129]
  2 peer_addr[yq01-spi-mx38:29129]
  3 peer_addr[yq01-ps-beehive-agent3677:29082]
  4 peer_addr[yq01-spi-mx38:29129]
  5 peer_addr[yq01-spi-mx38:29129]
  6 peer_addr[yq01-spi-mx38:29129]
  7 peer_addr[yq01-ps-beehive-agent3677:29082]
  8 peer_addr[yq01-spi-mx38:29129]
  9 peer_addr[yq01-spi-mx38:29129]
 10 peer_addr[yq01-ps-beehive-agent3677:29082]
 11 peer_addr[yq01-spi-mx38:29129]
 12 peer_addr[yq01-ps-beehive-agent3677:29082]
 13 peer_addr[yq01-spi-mx38:29129]
 14 peer_addr[yq01-ps-beehive-agent3677:29082]
 15 peer_addr[yq01-spi-mx38:29129]
 16 peer_addr[yq01-spi-mx38:29129]
 17 peer_addr[yq01-ps-beehive-agent3677:29082]
 18 peer_addr[yq01-spi-mx38:29129]
 19 peer_addr[yq01-spi-mx38:29129]
 20 peer_addr[yq01-ps-beehive-agent3677:29082]
 21 peer_addr[yq01-spi-mx38:29129]
 22 peer_addr[yq01-ps-beehive-agent3677:29082]
 23 peer_addr[yq01-spi-mx38:29129]

Я хочу подсчитать частоту имен машин в нескольких файлах журнала с помощью сценария оболочки. Я использую AWK так:

awk -F'[]:[]' '/peer_addr/{map[$2]+=1} END{for(key in map) {sum+=map[key];printf("%-15s %s\n", key, map[key]);} print "sum:",sum}' ${log_file_dir}/${log_path} >> ./conclusion/sum.log &

Видимо, нам нужна структура карты для сохранения и обновления результата. Тогда у меня есть проблема, что структура карты в AWK просто используется в собственном AWK. Я не могу суммировать результат в нескольких файлах журнала.

Мое временное решение - использовать AWK для вывода результатов каждого файла журнала в один файл, а затем снова использовать AWK для этого файла, чтобы суммировать результат.

У вас есть более эффективный подход?


person Griyn    schedule 02.07.2018    source источник
comment
Вы можете передать все файлы журнала в одну и ту же программу Awk, и она будет накапливать результат в нескольких файлах. Итак, вы делаете awk '{...}' <file1> <file2> <file3> ....   -  person kvantour    schedule 02.07.2018
comment
Спасибо! Одна проблема в том, что файлов слишком много. Я попробую прямо сейчас.   -  person Griyn    schedule 02.07.2018
comment
Пожалуйста, определите слишком много   -  person kvantour    schedule 02.07.2018
comment
На самом деле у меня есть тысячи файлов журналов, чтобы подсчитать частоту имен машин. Так что параметров файла AWK может быть слишком много.   -  person Griyn    schedule 02.07.2018
comment
Подумайте об использовании GNU Parallel для параллельной обработки ваших файлов и последующего объединения результатов в конце.   -  person Mark Setchell    schedule 02.07.2018
comment
Кажется, не имеет значения, в каком файле находятся имена машин, не так ли? Таким образом, вы можете просто объединить все файлы в awk с помощью find ... exec cat {} \; | awk ...   -  person Mark Setchell    schedule 02.07.2018
comment
Спасибо. Я выучу GNU Parallel. Вроде эффективнее.   -  person Griyn    schedule 02.07.2018
comment
Griyn, вы пробовали найти + cat, предложенную @ MarkSetchell? Мне кажется разумным (но для эффективности используйте exec cat {} +, если ваша находка поддерживает его).   -  person Ed Morton    schedule 02.07.2018


Ответы (1)


Если у вас большое количество файлов, намного превышающее максимально допустимый список аргументов, вы можете использовать Awk следующим образом:

  1. Создайте файл со всеми вашими файлами, которые вы хотите обработать.

    $ find <logroot> -type f -iname '*.yq01' > <logroot>/logfiles.txt
    
  2. Используйте awk для создания самого ARGV списка:

    $ awk -F'[]:[]' '(NR==FNR){ARGV[ARGC++]=$0; next}
                     /peer_addr/{map[$2]++}
                     END{ for(key in map) {
                             sum+=map[key];
                             printf("%-15s %s\n", key, map[key]);
                          }
                          print "sum:",sum }
                    ' <logroot>/logfiles.txt
    

ARGC: количество элементов в массиве ARGV.

ARGV: Массив аргументов командной строки, исключая параметры и аргумент программы, пронумерованных от нуля до ARGC-1. Аргументы в ARGV могут быть изменены или добавлены; ARGC можно изменить. Когда каждый входной файл заканчивается, awk обрабатывает следующий ненулевой элемент ARGV до текущего значения ARGC-1 включительно как имя следующего входного файла. Таким образом, установка для элемента ARGV значения null означает, что он не должен рассматриваться как входной файл. Имя '-' обозначает стандартный ввод. Если аргумент соответствует формату операнда присваивания, этот аргумент должен рассматриваться как присваивание, а не как аргумент файла.

Источник: стандарт awk POSIX

параллельная обработка:

Если вы хотите выполнить некоторую параллельную обработку, вас может заинтересовать GNU parallel :

$ cat <logroot>/logfiles.txt              \
   | parallel --jobs 4 ./process_files.sh \
   | awk '{map[$1]+=$2}
          END{ for(key in map) {
                  sum+=map[key];
                  printf("%-15s %s\n", key, map[key]);
               }
               print "sum:",sum
             }'

с process_files.sh:

#!/usr/bin/env bash
awk -F'[]:[]' '(NR==FNR){ARGV[ARGC++]=$0; next}
               /peer_addr/{map[$2]++}
               END{ for(key in map) {
                      sum+=map[key];
                      printf("%-15s %s\n", key, map[key]);
                    }}' "$@"
person kvantour    schedule 02.07.2018
comment
Спасибо за ваш ответ. Оно работает. Конечно серийно исполняется. Миссия слишком медленная. Параллельное исполнение более бесподобно. - person Griyn; 02.07.2018
comment
Размер файлов журнала должен быть не менее 100 ГБ. - person Griyn; 02.07.2018
comment
@Griyn Также примите во внимание, что жесткие диски не выполняют параллельное чтение / запись. Очевидно, что с буфером чтения и настройкой его размера в зависимости от количества параллельных процессов вы можете найти оптимальный вариант. - person kvantour; 02.07.2018
comment
@Griyn Я написал версию с использованием GNU parallel, возможно, это можно было бы улучшить. Если вам нужно сделать это один раз, я предлагаю запустить его и записать результат в один файл, чтобы вы могли повторно обработать его позже без необходимости обрабатывать 100 ГБ заново. - person kvantour; 02.07.2018
comment
примите во внимание, что жесткие диски не выполняют параллельное чтение / запись - вы правы, я проигнорировал этот момент. - person Griyn; 02.07.2018