我有一个包含100,000行xml事务的巨大日志
许多行包含重复的条目,例如帐户ID我想grep / sed或awk这些帐户ID的排序并显示唯一结果或计算它。
以下是我试图grep / sed / awk的模式
<Account Id="123456789012">
到目前为止,我已经尝试了以下内容:
sort 20150229.log | grep '<Account Id="*">' | uniq | wc -l
但我得到0结果......
请告知
感谢
答案 0 :(得分:0)
我有这样的别名,因为我经常遇到它:
alias cnt='sort -if |uniq -ic |sort -ifn' # case insensitive
alias CNT='sort |uniq -c |sort -n' # strict, case sensitive
这会对输入进行排序(-i
忽略非打印字符,-f
忽略大小写)然后使用uniq
(只能处理预先排序的数据,-i
就是这种情况不敏感,-c
计算重复次数),然后按数字排序(-n
为数字)。 (注意:cnt
输出的最终案例可能比预期更大写,因为命令如何纠正案例差异。)
调用它:
cat 20150229.log |cnt
cnt
的参数将传递给最终sort
命令,因此您可以使用-r
之类的标志来反转排序。我建议通过tail
或awk '$1 > 5'
之类的方式运行它,以消除所有小条目。
以上内容适用于日志等随机文本文件。解析HTML或XML是Bad Idea™,除非您完全了解要解析的确切格式。
也就是说,你有一个grep
查询,其中有一个有缺陷的正则表达式来匹配XML:
grep '<Account Id="*">'
这匹配<Account Id="">
(以及您可能不需要的<Account Id=">
和<Account Id=""">
),但它与您的示例<Account Id="123456789012">
不匹配。该正则表达式中的*
查找前一个字符("
)中的零个或多个。这是a more thorough explanation。
您需要.
代表任何字符(explanation here):
grep '<Account Id=".*">'
此外,除非你给它grep
标志,否则-x
将不匹配实线,我猜你不想要它,因为如果周围有空格,它将会失败(看到上面的Bad Idea™链接!)。这是grep的一个更便宜的版本,利用我的别名:
grep '<Account Id=' 20150229.log |cnt
答案 1 :(得分:0)
使用解析器非常容易。我喜欢XML::Twig
这类工作,因为你可以随时清除。
但是像:
#!/usr/bin/env perl
use strict;
use warnings;
my %count_of;
sub count_unique_id {
my ( $twig, $account ) = @_;
my $id = $account->att('id');
print "New ID: $id\n" unless $count_of{$id};
$count_of{$id}++;
$twig -> purge;
}
my $twig = XML::Twig -> new ( twig_handlers => { 'Account' => \&count_unique_id } );
$twig -> parsefile ( 'your_file.xml');
foreach my $id ( keys %count_of ) {
print "$id => $count_of{$id}\n";
}
print "There were ", scalar keys %count_of, " unique IDs\n";
答案 2 :(得分:0)
如果您对XML的规律性有信心并且不觉得需要使用XML感知工具,那么以下可能就足够了,并且具有一些优点,例如:它不需要gawk
,同时仍然可以容忍小的变化:
awk -v RS='<' '/^Account +Id *=/ { sub(/^[^=]*= *"/,""); sub(/".*/, ""); print}' |
sort | uniq
如果您想避免排序,那么您可以轻松修改awk脚本,例如如下:
awk -v RS='<' '
/^Account +Id *=/ { sub(/^[^=]*= *"/,""); sub(/".*/, ""); m[$0]}
END {for (i in m) {print i}}'
答案 3 :(得分:0)
您还没有向我们展示任何可测试的样本输入和预期输出,所以它可以猜测,但这可能是您想要的:
awk 'sub(/.*<Account Id="/,"") && sub(/".*/,"") && !seen[$0]++' 20150229.log