代码之家  ›  专栏  ›  技术社区  ›  Dan Dyer

使用awk处理每个记录具有不同固定宽度字段的文件

  •  3
  • Dan Dyer  · 技术社区  · 15 年前

    我有一些旧系统的数据文件,我想用awk处理。每个文件都包含一个记录列表。有几个不同的记录类型,每个记录类型都有一组不同的固定宽度字段(没有字段分隔符)。记录的前两个字符表示类型,从中您可以知道后面应该是哪些字段。文件可能如下所示:

    AAField1Field2LongerField3
    BBField4Field5Field6VeryVeryLongField7Field8
    CCField99
    

    使用gawk我可以设置 FIELDWIDTHS ,但这适用于整个文件(除非我缺少某种按记录设置的方法),或者我可以将fs设置为“”并一次处理一个字符,但这有点麻烦。

    有没有一种好的方法可以使用awk从这样的文件中提取字段?

    编辑 是的,我 能够 使用Perl(或其他东西)。不过,我还是很想知道是否有一种明智的方法来对付awk。

    6 回复  |  直到 11 年前
        1
  •  8
  •   Darren Atkinson    15 年前

    希望这会引导你走上正确的方向。假设您的多行记录被一个“cc”类型的行终止,您可以使用简单的if-then逻辑预处理您的文本文件。我假设您在一行中需要字段1、5和7,而awk脚本示例将是。

    BEGIN {
            field1=""
            field5=""
            field7=""
    }
    {
        record_type = substr($0,1,2)
        if (record_type == "AA")
        {
            field1=substr($0,3,6)
        }
        else if (record_type == "BB")
        {
            field5=substr($0,9,6)
            field7=substr($0,21,18)
        }
        else if (record_type == "CC")
        {
            print field1"|"field5"|"field7
        }
    }
    

    创建一个名为program.awk的awk脚本文件,并将该代码弹出其中。执行脚本时使用:

    awk -f program.awk < my_multi_line_file.txt 
    
        2
  •  5
  •   Aleksey Otrubennikov    15 年前

    你可以用两次传球:

    1步awk

    /^AA/{printf "2 6 6 12"    }
    /^BB/{printf "2 6 6 6 18 6"}
    /^CC/{printf "2 8"         }
    {printf "\n%s\n", $0}
    

    2阶梯锥度

    NR%2 == 1 {FIELDWIDTHS=$0}
    NR%2 == 0 {print $2}
    

    然后

    awk -f 1step.awk sample  | awk -f 2step.awk
    
        3
  •  4
  •   Jonathan Leffler    15 年前

    你可能需要抑制(或者至少忽略) awk 的内置字段分隔代码,并沿以下行使用程序:

    awk '/^AA/ { manually process record AA out of $0 }
         /^BB/ { manually process record BB out of $0 }
         /^CC/ { manually process record CC out of $0 }' file ...
    

    手工处理会有点麻烦-我想您需要使用 substr 函数按位置提取每个字段,所以我得到的每种记录类型的一行更像每种记录类型的一行,再加上后续打印。

    我确实认为你最好使用Perl及其 unpack 特征,但 AWK 也可以处理,尽管是口头的。

        4
  •  3
  •   Tim Cooper    11 年前

    您可以使用Perl,然后根据行的前两个字符选择一个解包模板吗?

        5
  •  0
  •   Petar Kabashki    15 年前

    最好使用一些功能齐全的脚本语言,如Perl或Ruby。

        6
  •  0
  •   Zsolt Botykai    15 年前

    那两个脚本呢?例如,第一个脚本根据第一个字符插入字段分隔符,然后第二个脚本应该处理它?

    或者首先在awk脚本中定义一些函数,它根据输入将行拆分为变量-我这样做是为了可能的重用。