Как я могу создать несколько счетчиков из файла, не перечитывая его несколько раз? - PullRequest
0 голосов
/ 20 июня 2019

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

Быстрый и грязный это:

for hour in 0{0..9} {10..23}
do
  grep $QUERY $FILE | egrep -c "^\S* $hour:"
  # or, alternately
  # egrep -c "^\S* $hour:.*$QUERY" $FILE
  # not sure which one's better
done

Но эти файлы занимают в среднем 15-20 миллионов строк, и я действительно не хочу анализировать каждый файл 24 раза. Было бы гораздо эффективнее проанализировать файл и посчитать каждый экземпляр $hour за один раз. Есть ли способ сделать это?

Ответы [ 3 ]

1 голос
/ 20 июня 2019

Предполагается, что отметка времени отображается с пробелом до 2-значного часа, а после двоеточия -

.
gawk -v patt="$QUERY" '
    $0 ~ patt && match($0, / ([0-9][0-9]):/, m) {
        print > (m[1] "." FILENAME)
    }
' "$FILE"

Это создаст 24 файла.

Требуется GNU awk для 3-аргументной формы матча ()

1 голос
/ 20 июня 2019

Вы можете попросить grep вывести соответствующую часть каждой строки с помощью -o, а затем использовать uniq -c для подсчета результатов:

grep "$QUERY" "$FILE" | grep -o "^\S* [0-2][0-9]:" | sed 's/^\S* //' | uniq -c

Команда sed предназначена для сохранения толькодвузначный час и двоеточие, которое вы также можете удалить с помощью другого выражения sed, если хотите.

Предостережения: это решение работает с GNU grep и GNU sed и не будет выдавать никакого вывода, вместо «0»,в течение нескольких часов без записей в журнале.Спасибо @EdMorton за то, что они указали на эти проблемы в комментариях и другие проблемы, которые были исправлены в ответе выше.

0 голосов
/ 20 июня 2019

Это, вероятно, то, что вам действительно нужно, используя GNU awk для 3-го аргумента для match () и делая предположения о том, как может выглядеть ваш ввод, что может содержать ваша переменная QUERY и как должен выглядеть вывод:

awk -v query="$QUERY" '
    match($0, " ([0-9][0-9]):.*"query, a) { cnt[a[1]+0]++ }
    END {
        for (hr=0; hr<=23; hr++) {
           printf "%02d = %d\n", hr, cnt[hr]
        }
    }
' "$FILE"

На самом деле не используйте весь верхний регистр для неэкспортированных переменных оболочки - см. Правильная капитализация переменных сценариев Bash и оболочки .

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