【问题标题】:grep, sed of awk a file for unique values then count the resultsgrep, sed of awk 一个文件的唯一值然后计算结果
【发布时间】:2016-06-12 19:46:25
【问题描述】:

我有一个巨大的日志,其中包含 100,000 行 xml 事务

许多行包含重复的条目,例如帐户 ID,我想 grep/sed 或 awk 这些帐户 ID 的排序并显示唯一结果或计数。

下面是我试图 grep/sed/awk 的模式

<Account Id="123456789012">

到目前为止,我已经尝试了以下方法:

sort 20150229.log | grep '<Account Id="*">' | uniq | wc -l

但我得到 0 个结果....

请指教

谢谢

【问题讨论】:

  • 编辑您的问题以包含一些简洁、可测试的样本输入和预期输出,以便我们可以帮助您但一目了然 - * 表示 zero or more repetitions of the preceding regexp segment,您应该使用 [^"]* 而不是 @987654326 @。不过,您的方法也存在其他问题。
  • 使用 XML/HTML 解析器(xmllint、xmlstarlet ...)。
  • sort 本身可以为您制作独特的线条。试试grep -E '&lt;Account Id="[^"]+"' acct.txt | sort -u | wc -l

标签: awk sed grep


【解决方案1】:

计算文本文件中的唯一行数

因为我经常遇到这种事情,所以我有一个别名:

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 之类的标志来反转排序。我建议通过tailawk '$1 &gt; 5' 之类的方式运行它以消除所有小条目。

 

解析 XML

以上内容非常适用于日志等随机文本文件。解析 HTML 或 XML 是 Bad Idea™,除非您完全了解要解析的确切格式。

也就是说,您有一个 grep 查询,其中包含有缺陷的正则表达式来匹配 XML:

grep '<Account Id="*">'

这匹配&lt;Account Id=""&gt;(以及&lt;Account Id="&gt;&lt;Account Id="""&gt;,您可能不想要),但它与您的示例&lt;Account Id="123456789012"&gt; 不匹配。该正则表达式中的* 查找零个或多个前一个字符(")。这里是a more thorough explanation

你需要一个. 来代表任何字符(explanation here):

grep '<Account Id=".*">'

此外,grep 不会匹配整行,除非你给它-x 标志,我猜你不希望这样,因为如果周围有空格,它将失败(见上面的坏Idea™ 链接!)。这是该 grep 的一个更便宜的版本,使用我的别名:

grep '<Account Id=' 20150229.log |cnt

【讨论】:

    【解决方案2】:

    使用解析器非常容易。我喜欢 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"; 
    

    【讨论】:

      【解决方案3】:

      如果您对 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}}' 
      

      【讨论】:

        【解决方案4】:

        您没有向我们展示任何可测试的样本输入和预期输出,所以这是一个猜测,但这可能是您想要的:

        awk 'sub(/.*<Account Id="/,"") && sub(/".*/,"") && !seen[$0]++' 20150229.log
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-19
          • 2018-10-10
          • 2021-09-19
          • 2014-08-01
          相关资源
          最近更新 更多