Найти наиболее встречающиеся слова в текстовом файле - PullRequest
0 голосов
/ 26 ноября 2018

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

например, log.:

Mon, 26 Nov 2018 07:51:07 +0100 | 164: [ERROR ***] Category ID not found for 'mcat-name1' 'subcat-name1' ref: '073' 
Mon, 26 Nov 2018 07:51:08 +0100 | 278: [ERROR ***] Category ID not found for 'mcat-name2' 'subcat-name2' ref: '020' 

Теперь я хочу определить 10 самых неудачных категорий.

Используя sed:

sed -e 's/\s/\n/g' < file.log | grep ERROR | sort | uniq -c | sort -nr  | head  -10

Я получаю 1636 [ОШИБКА

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

139 category1
23 category 2
...

Ответы [ 5 ]

0 голосов
/ 27 ноября 2018

Использование Perl

> cat merlin.txt
Mon, 26 Nov 2018 07:51:07 +0100 | 164: [ERROR ***] Category ID not found for 'mcat-name1' 'subcat-name1' ref: '073'
Mon, 26 Nov 2018 07:51:08 +0100 | 278: [ERROR ***] Category ID not found for 'mcat-name2' 'subcat-name2' ref: '020'
Mon, 26 Nov 2018 07:51:21 +0100 | 1232: [ERROR ***] Category ID not found for 'make' 'model' ref: '228239'
> perl -ne ' { s/(.*)Category.*for(.+)ref.*/\2/g and s/(\047\S+\047)/$kv{$1}++/ge if /ERROR/}  END { foreach (sort keys %kv) { print "$_ $kv{$_}\n" } } ' merlin.txt | sort -nr
'subcat-name2' 1
'subcat-name1' 1
'model' 1
'mcat-name2' 1
'mcat-name1' 1
'make' 1
>
0 голосов
/ 27 ноября 2018

Вы говорите, что хотите сделать подсчет, используя sed, но на самом деле у вас есть целый конвейер с sed, grep, sort, uniq и head.Как правило, когда это происходит, ваша проблема кричит для awk:

awk 'BEGIN{FS="\047"; PROCINFO["sorted_in"]="@val_num_asc"}
     /\[ERROR /{c[$2]++}
     END{for(i in c) { print c[i],i; if(++j == 10) exit } }' file

Приведенное выше решение является решением GNU awk, поскольку оно использует функции, не совместимые с POSIX, такие как сортировка обхода массива(PROCINFO).Разделитель полей установлен на('), который имеет восьмеричное значение \047, поскольку предполагает, что имя категории находится в одинарных кавычках.

Если вы не используете GNU awk, вы можете использовать sort и head или сделатьсортировка себя.Один из способов:

awk 'BEGIN{FS="\047"; n=10 }
     /\[ERROR /{ c[$2]++ }
     END {
       for (l in c) {
         for (i=1;i<=n;++i) { 
           if (c[l] > c[s[i]]) {
             for(j=n;j>i;--j) s[j]=s[j-1];
             s[i]=l
             break
           }
         }
       }
       for (i=1;i<=n;++i) {
         if (s[i]=="") break
         print c[s[i]], s[i]
       }
     }' file

или просто сделать:

awk 'BEGIN{FS="\047"}
     /\[ERROR /{c[$2]++}
     END{for(i in c) { print c[i],i; if(++j == 10) exit } }' file \
| sort -nr | head -10
0 голосов
/ 26 ноября 2018

Предполагая, что 'Bulgari' является примером категории, которую вы хотите извлечь, попробуйте

sed -n "s/.*ERROR.*\] Category '\([^']*\)'.*/\1/p" file.log |
sort | uniq -c | sort -rn | head -n 10

Команда sed находит строки, которые соответствуют довольно сложному регулярному выражению, и захватывает часть строки, затемзаменяет совпадение захваченной подстрокой и печатает ее (опция -n отключает действие печати по умолчанию, поэтому мы печатаем только извлеченные строки).Остальное в основном идентично тому, что у вас уже было.

В регулярном выражении мы ищем (начало строки, за которым следует) все (кроме новой строки), за которым следует ERROR, а затем - ] Category 'и затем строка, которая не содержит ни одной кавычки, затем закрывающая одинарная кавычка, за которой следует что-нибудь.Много «что-нибудь (кроме новой строки)» требуется для того, чтобы заменить всю строку только захваченной строкой внутри одинарных кавычек.Скобки с обратной косой чертой - это то, что фиксирует выражение;Google для "backref" для полного совка.

Ваша первоначальная попытка будет только извлечь фактические ERROR строки, потому что вы заменили все окружающие пробелы с новыми строками (предполагая, что ваш sed принимает Perl \s сокращение, которое не является стандартным в sed, и что \n интерпретируется как буквальный перевод строки в замене, которая также не является полностью стандартной или переносимой).

0 голосов
/ 26 ноября 2018

Способ состоит в том, чтобы выбрать категории с ошибками и заменить всю строку только именем категории, используя sed.

Попробуйте:

sed -e "s/^.* [[]ERROR .*[]] Category '\([^']*\)' .*$/\1/g" file.log | sort  | uniq -c | sort -nr | head -16

^ - начало строки

\( ... \): последовательность символов, заключенную в эту экранированную скобку, может указываться с помощью \1 для первой пары, встречающейся в регулярном выражении, \2 для второй пары и т. Д..

$ - это конец строки.

sed выбирает строку, содержащую [ERROR и некоторые символы до ], свернутые словом Category, а затем после (пробела) выбирается любая последовательность символов, вплоть до следующего пробела, с парой экранированных скобок, за которой следует любая последовательность символов до конца строки.Если такая строка найдена, она заменяется последовательностью символов после Category.

0 голосов
/ 26 ноября 2018

Вы получили 1636 [ERROR, потому что вы заменяете пробел на символ новой строки, затем вы добавляете слово ERROR, затем считаете.

This:

sed -e 's/\s/\n/g' < file.log | grep ERROR 

Дает вам это:

[ERROR
[ERROR
[ERROR
[ERROR
[ERROR
[ERROR
... (1630 more)

Сначала вам нужно выполнить grep, а затем sed (я уверен, что вы можете добиться большего успеха с помощью sed, но я просто говорю о логике команд):

grep ERROR file.log | sed -e 's/\s/\n/g' | sort | uniq -c | sort -nr | head -10

Этоможет быть не лучшим решением, так как он считает слово ERROR и другие бесполезные слова, но вы не дали нам много информации о входном файле.

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