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

问题描述 投票:0回答:7

我有一些来自遗留系统的数据文件,我想使用 Awk 处理它们。每个文件由一个记录列表组成。有多种不同的记录类型,每种记录类型都有一组不同的固定宽度字段(没有字段分隔符)。记录的前两个字符指示类型,由此您可以知道应该遵循哪些字段。文件可能看起来像这样:

AAField1Field2LongerField3
BBField4Field5Field6VeryVeryLongField7Field8
CCField99

使用 Gawk 我可以设置 FIELDWIDTHS,但这适用于整个文件(除非我错过了逐条记录设置此设置的某种方法),或者我可以将 FS 设置为“”并处理文件一次一个字符,但这有点麻烦。

有没有好的方法使用 Awk 从这样的文件中提取字段?

编辑:是的,我可以使用Perl(或其他东西)。不过,我仍然很想知道是否有一种明智的方法可以使用 Awk 来实现这一点。

linux unix awk text-processing gawk
7个回答
8
投票

希望这能引导您走向正确的方向。假设您的多行记录保证以“CC”类型行终止,您可以使用简单的 if-then 逻辑预处理文本文件。我假设您需要将 fields1,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 

5
投票

您也许可以使用两次通行证:

1step.awk

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

2step.awk

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

然后

awk -f 1step.awk sample  | awk -f 2step.awk

4
投票

您可能需要抑制(或至少忽略)

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
也可以处理它,尽管很冗长。


3
投票

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


1
投票

一个

awk
想法,使用数组来跟踪不同的
FIELDWIDTHS
格式:

awk '
BEGIN { fw["AA"] = "2 6 6 12"                     # predefined FIELDWIDTHS
        fw["BB"] = "2 6 6  6 18 6"
        fw["CC"] = "2 7"
      }
      { FIELDWIDTHS = fw[substr($0,1,2)]          # dynamically define FIELDWIDTHS based on 1st two characters
        $0 = $0                                   # force reparse of input line based on new FIELDWIDTHS
        print "#############",$0
        for (i=1;i<=NF;i++)
            print "field #"i,":",$i
      }
' input.txt

这会生成:

############# AAField1Field2LongerField3
field #1 : AA
field #2 : Field1
field #3 : Field2
field #4 : LongerField3
############# BBField4Field5Field6VeryVeryLongField7Field8
field #1 : BB
field #2 : Field4
field #3 : Field5
field #4 : Field6
field #5 : VeryVeryLongField7
field #6 : Field8
############# CCField99
field #1 : CC
field #2 : Field99

0
投票

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


0
投票

2 个脚本怎么样?例如。第一个脚本根据第一个字符插入字段分隔符,然后第二个脚本应该处理它?

或者首先在 AWK 脚本中定义一些函数,该函数根据输入将行拆分为变量 - 我会这样做,以便可能的重新使用。

© www.soinside.com 2019 - 2024. All rights reserved.