3

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

AAField1Field2LongerField3
BBField4Field5Field6VeryVeryLongField7Field8
CCField99

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

有没有一种使用 Awk 从此类文件中提取字段的好方法?

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

4

6 回答 6

8

希望这将引导您朝着正确的方向前进。假设您的多行记录保证由“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 
于 2009-09-08T13:23:42.870 回答
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
于 2009-09-08T12:53:53.470 回答
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也可以处理它,尽管很冗长。

于 2009-09-08T12:21:12.380 回答
3

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

于 2009-09-08T11:48:25.987 回答
0

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

于 2009-09-08T11:37:21.670 回答
0

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

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

于 2009-09-08T12:19:56.660 回答