Unix 查找文本文件中出现最多的单词

Unix 查找文本文件中出现最多的单词,unix,command-line,text-processing,Unix,Command Line,Text Processing,我有一个日志文件,记录失败的cat和sub cat名称,并显示错误消息。我的目标是找到最常见的类别 e、 g.日志: 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 f

我有一个日志文件,记录失败的cat和sub cat名称,并显示错误消息。我的目标是找到最常见的类别

e、 g.日志:

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[ERROR
,因为您将空格字符更改为换行符,然后将单词ERROR变灰,然后进行计数

这:

sed -e 's/\s/\n/g' < file.log | grep ERROR 
您首先需要grep,然后是sed(非常肯定您可以用sed做得更好,但我只是在谈论命令背后的逻辑):


这可能不是最好的解决方案,因为它会计算单词错误和其他无用的单词,但您没有向我们提供有关输入文件的大量信息。

假设
'Bulgari'
是您要提取的类别的一个示例,请尝试

sed -n "s/.*ERROR.*\] Category '\([^']*\)'.*/\1/p" file.log |
sort | uniq -c | sort -rn | head -n 10
sed
命令查找与相当复杂的正则表达式匹配的行并捕获部分行,然后用捕获的子字符串替换匹配项并打印它(
-n
选项禁用默认打印操作,因此我们只打印提取的行).剩下的基本上和你已经有的一样

在正则表达式中,我们查找(行的开头后跟)任何内容(新行除外),后跟
ERROR
,然后再后跟
]Category'
,然后是不包含单引号的字符串,最后是单引号后跟任何内容。为了用单引号中捕获的字符串替换整行,需要大量的“任何内容(新行除外)”。反斜杠括号用于捕获表达式;谷歌的“backref”为完整的独家新闻


您最初的尝试只提取实际的
错误
字符串,因为您用换行符替换了所有周围的空格(模糊地假设您的
sed
接受Perl
\s
速记,这在
sed
中不是标准的,并且
\n
在替换中被解释为文字换行符,这也不完全是标准的或可移植的).

方法是选择错误的类别,并使用
sed
仅用类别名称替换整行

试一试:

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

\(…\)
:对于正则表达式中出现的第一对,可以使用
\1
引用此转义括号中包含的字符序列;对于第二对,可以使用
\2

$
是该行的结尾


sed
选择包含
[ERROR
和一些字符的行,直到
]
,后跟单词
Category
,然后在
之后(空格)char,任何字符序列,直到下一个空格char,都用一对转义括号进行选择,后面跟着任何字符序列,直到行尾。如果找到这样一行,它将被替换为
类别之后的char序列

您说要使用
sed
进行计数,但实际上,您是这样做的整个管道都有
sed
grep
sort
uniq
。通常,当这种情况发生时,您的问题是要求
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,您可以使用
排序
或自己进行排序。一种方法是:

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
使用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
>

请在您的帖子中发布更多关于输入和输出的解释性示例,然后让我们知道,因为它不清楚。同意@RavinderSingh13-您的示例中没有类别1,但您希望它在输出中;同时修复问题标题-似乎您在寻找一些东西,而不是单词本身。当然,
sed
是完美的le也可以执行
grep
的工作。See awk似乎是最好的解决方案。结果返回的类别带有一个数字,假设出现的数量,但不会在出现次数最多之后排序。@merlin您有输入文件的示例吗?下面是另一行,在ref number之后有更多的txt。make和model是我所要的尝试计数以识别错误最多的猫:2018年11月26日星期一07:51:21+0100 | 1232:[错误***]找不到“make”“model”ref:'228239'@merlin的类别ID,请您再多提供一行。我们需要您输入的示例。如何向stackoverflow添加文件?awk版本20070501
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
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
> 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
>