代码之家  ›  专栏  ›  技术社区  ›  abbood

如何使sed匹配具有多条线的图案

  •  2
  • abbood  · 技术社区  · 7 年前

    出身背景

    sed -ne '/pattern/ p' infile >outfile
    

    在代码中,我只是在日志行前面加上标识符,以便以后可以使用它们进行过滤(我的标识符是订单号和线程号..例如,这个日志行:

    9/14/2017 10:19:58 AM:::   ORD7123::TH41361::Failed Checkout
    

    7123 )将看起来像:

    sed -ne '/ORD7123/ p' infile >outfile
    

    问题

    9/14/2017 10:19:58 AM:::   ORD7123::TH41361::Failed Checking Out With Credit Card for # 3 times. Error: {
      "order": "country is required",
      "credit_card": "year is not a valid year"
    }.
    9/14/2017 10:19:59 AM:::   ORD7123::TH41347::Successfully Got a something Solution  
    

    使用上述sed命令,我的输出将如下所示

    9/14/2017 10:19:58 AM:::   ORD7123::TH41361::Failed Checking Out With Credit Card for # 3 times. Error: {
    9/14/2017 10:19:59 AM:::   ORD7123::TH41347::Successfully Got a something Solution
    

    建议/分析

    我们以前遇到过这个问题(我们可以控制日志的创建),我们处理这个问题的方法是用 /n 或者类似的。在这种情况下,我对日志创建没有太多控制权,因此我必须按原样处理日志

    4 回复  |  直到 7 年前
        1
  •  1
  •   anubhava    7 年前

    awk 在多行上工作并收集日志消息。看看您的示例,您似乎希望在 { ... } 这涉及多行。因此,您可以使用以下链接:

    awk '/ORD7123/{if (/{$/) p=1; print; next} p; p && /^}/{p=0}' file.log
    

    如果你不总是有 { ... } 命令:

    awk '/ORD7123/ {p=NR} NR==p+1 {p = (/^[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4} / ? 0 : NR)} p' file
    
    9/14/2017 10:19:58 AM:::   ORD7123::TH41361::Failed Checking Out With Credit Card for # 3 times. Error: {
      "order": "country is required",
      "credit_card": "year is not a valid year"
    }.
    9/14/2017 10:19:59 AM:::   ORD7123::TH41347::Successfully Got a something Solution
    

    awk公司 命令在每个日志行中查找开始日期模式,如果未找到,则认为它是前一个日志消息的延续。

        2
  •  1
  •   RomanPerekhrest    7 年前

    解决方案:

    awk -v p="ORD7123" '$0~p{ print; 
               while(getline nl > 0 && (nl!~/^[0-9]+\/[0-9]{2}/ || nl~p)){ 
                   print nl 
               } 
           }' inputfile
    

    示例输出:

    9/14/2017 10:19:58 AM:::   ORD7123::TH41361::Failed Checking Out With Credit Card for # 3 times. Error: {
      "order": "country is required",
      "credit_card": "year is not a valid year"
    }.
    9/14/2017 10:19:59 AM:::   ORD7123::TH41347::Successfully Got a something Solution
    
        3
  •  1
  •   potong    7 年前

    这可能适用于您(GNU-sed):

    sed ':a;/ORD7123/!d;:b;n;/^..\?\/..\?\/.... ..:..:.. /ba;bb' file
    

    ORD7123 )否则删除该行。在匹配中,读取并打印后续行,直到以日期和时间开头的行,然后检查所需的字符串。

        4
  •  0
  •   Ed Morton    7 年前

    sed用于单个行上的简单替换, 仅此而已 . 你不想在一行上做简单的替换,所以你不应该考虑sed。只需使用awk:

    $ cat tst.awk
    /^[0-9]/ { prt() }
    { rec = (rec=="" ? "" : rec ORS) $0 }
    END { prt() }
    function prt() {
        if ( rec ~ /ORD7123/) {
            print rec
        }
        rec = ""
    }
    
    $ awk -f tst.awk file
    9/14/2017 10:19:58 AM:::   ORD7123::TH41361::Failed Checking Out With Credit Card for # 3 times. Error: {
      "order": "country is required",
      "credit_card": "year is not a valid year"
    }.
    9/14/2017 10:19:59 AM:::   ORD7123::TH41347::Successfully Got a something Solution
    

    如果您希望通过更改来简化进一步的处理,可以很容易地调整它以删除记录中间的换行符 ORS OFS (或您喜欢的任何其他字符串),其中记录正在编译:

    $ cat tst.awk
    /^[0-9]/ { prt() }
    { rec = (rec=="" ? "" : rec OFS) $0 }
    END { prt() }
    function prt() {
        if ( rec ~ /ORD7123/) {
            print rec
        }
        rec = ""
    }
    
    $ awk -f tst.awk file
    9/14/2017 10:19:58 AM:::   ORD7123::TH41361::Failed Checking Out With Credit Card for # 3 times. Error: {   "order": "country is required",   "credit_card": "year is not a valid year" }.
    9/14/2017 10:19:59 AM:::   ORD7123::TH41347::Successfully Got a something Solution