使用awk如何将固定宽度的多行记录转换为单行记录

使用awk如何将固定宽度的多行记录转换为单行记录,awk,Awk,我想将固定宽度的文件多行记录转换为单行记录。该文件包含4个字段: 日期戳,严重性,错误代码,消息类型根据字段中的数据,记录数据可以跨越多行。例如 日期戳字段宽度为10个字符-但数据值为19个字符,因此它跨越两行。前10个字符在第一行,后9个字符在第二行 字段位置 日期戳=1-10 severity=12-17[这些值可能是错误、信息、警告,因此如果该值是警告,则剩余数据将放在12-17的第二行中] 错误代码=18-25 消息=26-70 记录之间没有空行 2014-02-21 INFO UTF8

我想将固定宽度的文件多行记录转换为单行记录。该文件包含
4个字段
日期戳
严重性
错误代码
消息类型
根据字段中的数据,记录数据可以跨越多行。例如
日期戳
字段宽度为
10个
字符-但数据值为
19个
字符,因此它跨越两行。前10个字符在第一行,后9个字符在第二行

字段位置

日期戳=1-10 severity=12-17[这些值可能是错误、信息、警告,因此如果该值是警告,则剩余数据将放在12-17的第二行中] 错误代码=18-25 消息=26-70

记录之间没有空行

2014-02-21 INFO UTF8_INT  Starting execution of workflow
07:01:59                  [wf_router] in domain.

2014-02-21 error UTF8_INT  SQ_ff:Exchange: Rowdata: ( RowType=0
07:01:59                 (insert) Src Rowid=1 TargIELD:Char.500:):
                          ".Improved By Resting
                         [[<~a~>Resting<~a0~>]]|Lying Down
                         [[<FNT><!>no Lying Down]]).

2014-02-21 warni UTF8_INT  SQ_ff:Exchange: Rowdata: ( RowType=0
           ng              (insert) Src Rowid=1 TargIELD:Char.500:):
                          ".Improved By Resting
                         [[<~a~>Resting<~a0~>]]|Lying Down
                         [[<FNT><!>no Lying Down]]).

虽然awk设计用于使用字段分隔符(默认情况下为空白),但awk也可以读取固定宽度的文件。要检索宽度为w的字段,从p列开始(其中1是行中最左侧的位置),请使用
substr($0,p,w)
。要跨行累积列数据,只需在每列中使用一个变量即可

{
    if (/[^ \t]/) {
        datetime = datetime " " trim(substr($0, 1, 10));
        severity = severity substr($0, 12, 5);
        errorcode = errorcode substr($0, 18, 8);
        message = message " " trim(substr($0, 26));
    }
    else {
        output();
        datetime = severity = errorcode = message = "";
    }
}

END {
    output();
}

function output() {
    if (datetime || severity || errorcode || message) {
        print trim(datetime) " ; " trim(severity) " ; " trim(errorcode) " ; " trim(message);
    }
}

function trim(s) {
    gsub(/^[ \t]+|[ \t]+$/, "", s);
    return s;
}
输入(注意我在第1行对
UTF8\u INT
的对齐进行了消毒):

输出:

2014-02-21 07:01:59 ; INFO ; UTF8_INT ; Starting execution of workflow [wf_router] in domain.
2014-02-21 07:01:59 ; error ; UTF8_INT ; SQ_ff:Exchange: Rowdata: ( RowType=0 (insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting [[<~a~>Resting<~a0~>]]|Lying Down [[<FNT><!>no Lying Down]]).
2014-02-21 ; warning ; UTF8_INT ; SQ_ff:Exchange: Rowdata: ( RowType=0 (insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting [[<~a~>Resting<~a0~>]]|Lying Down [[<FNT><!>no Lying Down]]).
注:

  • 由于您没有回答我的所有问题,我无法知道脚本是否符合您的所有要求
  • 假设在输出数据中需要分号作为字段分隔符,我想知道如何处理输入数据中已经存在的分号。我应该采取某种逃避方式吗

    • 您需要这样的东西(使用GNU awk进行各种扩展):

      $cat tst.awk
      开始{FIELDWIDTHS=“10 1 5 1 8 45”}
      /^[0-9]{4}(-0-9]{2}{2}/&(NR>1){prtrec()}
      {
      
      对于(i=1;iWhy是
      UTF8\u INT
      在第1行中未对齐的,这是打字错误吗?为什么
      warning
      在第17列中没有第一个“n”(您的规范状态为12-17,但这更像是12-16)?“记录之间没有空行”,您如何判断记录的结束位置?或者我误解了您对“中间”一词的解释?最后但并非最不重要的是,所需的输出是什么?我输入了一些示例数据只是为了显示记录。我想将此数据转换为单行记录格式,2014-02-21 07:01:59;INFO;UTF8_INT;开始执行工作流[wf_router]在域中。你能解释一下函数prtrec()的逻辑吗?{n=split(“1 3 5 6”,f)for(i=1;i你认为它是什么,我来填补空白?非常感谢你的快速回复。你的两个逻辑都是正确的
      2014-02-21 07:01:59 ; INFO ; UTF8_INT ; Starting execution of workflow [wf_router] in domain.
      2014-02-21 07:01:59 ; error ; UTF8_INT ; SQ_ff:Exchange: Rowdata: ( RowType=0 (insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting [[<~a~>Resting<~a0~>]]|Lying Down [[<FNT><!>no Lying Down]]).
      2014-02-21 ; warning ; UTF8_INT ; SQ_ff:Exchange: Rowdata: ( RowType=0 (insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting [[<~a~>Resting<~a0~>]]|Lying Down [[<FNT><!>no Lying Down]]).
      
      $ cat tst.awk
      BEGIN { FIELDWIDTHS="10 1 5 1 8 45" }
      
      /^[0-9]{4}(-[0-9]{2}){2}/ && (NR>1) { prtrec() }
      
      {
          for (i=1;i<=NF;i++) {
              rec[i] = rec[i] $i
          }
      }
      
      END { prtrec() }
      
      function prtrec() {
          n=split("1 3 5 6",f)
          for (i=1;i<=n;i++) {
              gsub(/^\s+|\s+$/,"",rec[f[i]])
              printf "%s%s", rec[f[i]], (i<n?OFS:ORS)
          }
          delete rec
      }
      
      $ gawk -f tst.awk file
      2014-02-2107:01:59 INFO UTF8_INT Starting execution of workflow [wf_router] in domain.
      2014-02-2107:01:59 error UTF8_INT SQ_ff:Exchange: Rowdata: ( RowType=0(insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting[[&lt;~a~&gt;Resting&lt;~a0~&gt;]]|Lying Down[[&lt;FNT&gt;&lt;!&gt;no Lying Down]]).
      2014-02-21 warning UTF8_INT SQ_ff:Exchange: Rowdata: ( RowType=0  (insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting[[&lt;~a~&gt;Resting&lt;~a0~&gt;]]|Lying Down[[&lt;FNT&gt;&lt;!&gt;no Lying Down]]).