Как получить все строки, начиная с шаблонов из файла - PullRequest
0 голосов
/ 22 октября 2018

У меня есть файл журнала nginx, который я хочу разделить на несколько файлов на основе Ips.Например, у меня есть ips1.txt и ips2.txt.Каждый файл имеет половину числа уникальных ips файла журнала.Файл журнала nginx имеет следующий формат:

172.0.0.10 - [24/Jun/2018:11:00:00 +0000] url1 GET url2 HTTP/1.1 (200) 0.000 s 2356204 b url3 - - [HIT] - s - Mozilla/5.0 (X11; CrOS x86_64 10452.99.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.203 Safari/537.36 

172.0.0.11 - [24/Jun/2018:11:00:00 +0000] url1 GET url2 HTTP/1.1 (200) 0.000 s 307 b url3 - - [HIT] - s - Mozilla/5.0 (X11; CrOS x86_64 10452.99.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.203 Safari/537.36

Итак, все, что я делаю, чтобы получить все строки, начинающиеся с IP, который находится внутри моего файла шаблона:

cat log.txt | grep -f ips1.txt > part1.txt
cat log.txt | grep -f ips2.txt > part2.txt

Я знаю, что я занимаюсь поиском во всей строке, а не только в начале.Это замедляет поиск и тратит больше памяти, чем могло бы быть.Я знаю, что если у меня есть только один шаблон для поиска, я мог бы использовать awk (например, awk '{if($1 == "172.0.0.10")print;}' log.txt), но я не знаю, как сделать это с файлом шаблона, используя grep.

Так что я хочуэто тратить меньше памяти и ускорить поиск, просто посмотрев в начало строки.Мой файл журнала имеет много ГБ, и, если это возможно, я сэкономлю много времени.

РЕДАКТИРОВАТЬ:

Мои файлы ips * .txt создаются на основе количества потоков, которые у меня есть.Ниже вы можете увидеть, как мой код:

NUM_THREADS=8
export LC_ALL=C

unpigz -c log.gz | awk '{print $1;}' | LC_ALL=C sort -S 20% -u > all_ips.txt

lines_arq=$(wc -l all_ips.txt | cut -d' ' -f1)
lines_each_file=$(($lines_arq / $NUM_THREADS + 50))
split --lines=$lines_each_file all_ips.txt 2018/prefixo.

zgrep log.gz -Fwf 2018/prefixo.aa | pigz > file1.gz &
zgrep log.gz -Fwf 2018/prefixo.ab | pigz > file2.gz &
...
zgrep log.gz -Fwf 2018/prefixo.ah | pigz > file8.gz &

wait

unpigz -c file1.gz | pypy script.py -i - -o onOff -s 11:00:00 -m testing -y 2018 | pigz > onOff-file1.gz &
...
unpigz -c file8.gz | pypy script.py -i - -o onOff -s 11:00:00 -m testing -y 2018 | pigz > onOff-file8.gz &

Ответы [ 2 ]

0 голосов
/ 22 октября 2018

Вот несколько идей, чтобы ускорить ваши команды.Обязательно сравните их.Мне не хватало данных для их сравнения.

  • Использовать zgrep file сверх unpigz -c file | grep
  • Использовать быстрый языковой стандарт: LC_ALL=C zgrep ...
  • Использовать фиксированную строкупоиск -F вместе со словом регулярных выражений -w.Поиск по фиксированным строкам должен быть немного быстрее, чем стандартный поиск по регулярным выражениям.Для фиксированного строчного регистра регулярные выражения - это самое близкое, что вы можете получить к поиску »только в начале строки« .
    grep -Fwf ip....

или

  • Скомпилируйте свои ip-файлы в регулярные выражения и добавьте ^ в начало для поиска только в начале строк.Затем используйте grep -E или grep -P "$regex" / pcregrep "$regex".Скорость -E и -P может сильно отличаться.Проверьте оба, чтобы увидеть, какой из них быстрее.
regex="$(tr \\n \| < ips1.txt | sed 's/^/^(/;s/\./\\./g;s/$/)/')"
zgrep -E "$regex" yourfile > part1.txt
zgrep -Ev "$regex" yourfile > part2.txt
0 голосов
/ 22 октября 2018

Используйте awk для всего этого.Сначала прочитайте ваши исправленные строки, а затем разделите журнал.Например:

awk '{out[$1] = FILENAME ".out"} 
     END {while (getline < input) { print > out[$1] }}
' input=log.txt ips[12].txt

Чтение входного файла несколько раз приведет к снижению вашей производительности гораздо больше, чем лишние затраты на awk, без необходимости разбивающие строки.

Ниже приведено краткое объяснение кода.Первая (и единственная) команда должна прочитать входные данные и создать массив имен файлов.Список всех ips * .txt указан в качестве входных данных, поэтому эти строки считываются в массив.В идеале, эти файлы являются относительно небольшими, поэтому создание этого массива не займет много времени.После построения массива вы вводите предложение END, где вы читаете файл журнала (только один раз!) И записываете каждую строку в соответствующий файл.

Похоже, вы хотите динамически генерировать ips * .txt и просто хотите распространять журнал.В этом случае попробуйте что-то вроде:

awk '! ($1 in out) {out[$1] = (idx++ %10) } 
    { outfile= "output." out[$1] ".txt"; print > outfile ; next} ' log.txt

Это просто проверяет, видели ли вы уже ip: если вы уже видели его, запишите его в тот же файл, в котором вы записали предыдущий журнал.Если нет, увеличьте счетчик (мод 10 ... выберите свой модуль в зависимости от того, сколько файлов вы хотите) и запишите в этот файл, записав, где вы пишете строку.Повторите эти действия для каждой строки в журнале.

Ключ здесь состоит в том, чтобы минимизировать количество раз, когда вы читаете журнал.

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