我有一个日志文件,其中记录了因消息错误而失败的cat和sub cat名称。我的目标是找到出现次数最多的类别。
例如日志。
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'
现在,我想确定失败的十大类别。
使用sed:
sed -e 's/\s/\n/g' < file.log | grep ERROR | sort | uniq -c | sort -nr | head -10
我收到1636 [ERROR
虽然我一直在寻找出现次数增加后的类别列表。例如
139 category1
23 category 2
...
答案 0 :(得分:1)
您说您想使用sed
进行计数,但是实际上,您正在使用sed
,grep
,sort
,{{1} }和uniq
。通常,发生这种情况时,您的问题是为head
尖叫:
awk
上述解决方案是GNU awk解决方案,因为它利用了非POSIX兼容功能,例如数组遍历的排序(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
)。字段分隔符设置为PROCINFO
),它具有八进制值'
,因为它假定类别名称在单引号之间。
如果您不使用GNU awk,则可以使用\047
和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
答案 1 :(得分:0)
您之所以得到1636 [ERROR
是因为您将空格字符更改为换行符,然后将ERROR字词变成grep,然后再进行计数。
此:
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字和其他无用的字,但是您没有在输入文件中提供很多信息。
答案 2 :(得分:0)
假设'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
在替换中被解释为原义的换行符,这也不是完全标准或可移植的。
答案 3 :(得分:0)
方法是选择错误的类别,并使用sed
仅用类别名称替换整行。
尝试一下:
sed -e "s/^.* [[]ERROR .*[]] Category '\([^']*\)' .*$/\1/g" file.log | sort | uniq -c | sort -nr | head -16
^
是该行的开头
\( ... \)
:此正则表达式中出现的第一个对可以用转义括号括起来的char序列用\1
引用,对于第二对等用\2
可以引用。
$
是该行的结尾。
sed
选择一行包含[ERROR
和一些字符的行,直到]
,后跟单词Category
,然后在之后(空格)char,直到下一个空格char的任何char序列,都用一对转义的括号选择,然后是直到行末的任何char序列。如果找到这样的行,则将其替换为
Category
之后的char序列。
答案 4 :(得分:0)
使用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
>