Linux 使用Awk处理每个记录具有不同固定宽度字段的文件
我有一些来自遗留系统的数据文件,我想使用Awk处理这些文件。每个文件由一个记录列表组成。有几种不同的记录类型,每种记录类型都有一组不同的固定宽度字段(没有字段分隔符)。记录的前两个字符表示类型,通过这两个字符,您可以知道应该遵循哪些字段。文件可能如下所示:Linux 使用Awk处理每个记录具有不同固定宽度字段的文件,linux,unix,awk,text-processing,gawk,Linux,Unix,Awk,Text Processing,Gawk,我有一些来自遗留系统的数据文件,我想使用Awk处理这些文件。每个文件由一个记录列表组成。有几种不同的记录类型,每种记录类型都有一组不同的固定宽度字段(没有字段分隔符)。记录的前两个字符表示类型,通过这两个字符,您可以知道应该遵循哪些字段。文件可能如下所示: AAField1Field2LongerField3 BBField4Field5Field6VeryVeryLongField7Field8 CCField99 使用Gawk,我可以设置,但这适用于整个文件(除非我缺少某种方法来逐个记录地
AAField1Field2LongerField3
BBField4Field5Field6VeryVeryLongField7Field8
CCField99
使用Gawk,我可以设置,但这适用于整个文件(除非我缺少某种方法来逐个记录地设置),或者我可以将FS设置为“”,并一次处理一个字符,但这有点麻烦
有没有一种好方法可以使用Awk从这样的文件中提取字段
编辑:是的,我可以使用Perl(或其他东西)。不过,我仍然很想知道是否有一种明智的方法可以使用Awk。最好使用一些功能齐全的脚本语言,如perl或ruby。您可以使用perl,然后根据行的前两个字符选择一个解包模板吗?两个脚本怎么样?例如,第一个脚本根据第一个字符插入字段分隔符,那么第二个脚本应该处理它吗
或者首先在您的AWK脚本中定义一些函数,根据输入将行拆分为变量-为了可能的重复使用,我会这样做。您可能需要抑制(或至少忽略)
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
也可以处理它,尽管很冗长。您可能可以使用两个过程:
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步骤awk
NR%2 == 1 {FIELDWIDTHS=$0}
NR%2 == 0 {print $2}
然后
awk -f 1step.awk sample | awk -f 2step.awk
希望这将引导你走向正确的方向。假设您的多行记录保证由“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
awk-f program.awk
好的,谢谢。我已经十年没有接触过Perl了,但是如果我找不到一个明智的方法用Awk来实现这一点,我可能会听从你的建议;我写的没有错,但也不是最小的。你可以使用类似于Jonathan Leffler答案的匹配。然后进行子字符串提取。