多行记录中的AWK打印字段

时间:2015-06-04 23:44:12

标签: bash unix awk

我有一个包含多行字段的输入文件。在此文件中,根据查询大小重复字段模式。

ZZZZ
21293

YYYYY     XXX     WWWW   VV
13242     MUTUAL  BOTH   NO

UUUUU   TTTTTTTT  SSSSSSSS   RRRRR   QQQQQQQQ  PPPPPPPP
 3       0                    3       0

NNNNNN  MMMMMMMMM  LLLLLLLLL  KKKKKKKK  JJJJJJJJ
 2       0                     5         3

IIIIII  HHHHHH  GGGGGGG  FFFFFFF  EEEEEEEEEEE  DDDDDDDDDDD
 5       3       0                 3           

我想要的输出是每组字段一行。空 字段应标记。例如: “X”

21293 13242 MUTUAL BOTH NO 3 0 X 3 0 X 2 0 X 5 3 5 3 0 X 3 X
12345 67890 MUTUAL BOTH NO 3 0 X 3 0 X 2 0 X 5 3 5 3 0 X 3 X  

我一直在考虑如何使用awk / unix脚本获得所需的输出但无法弄明白。有任何想法吗?非常感谢!!!

2 个答案:

答案 0 :(得分:1)

这不适合awk的编程风格,它基于由模式分隔的字段,而不是在行上具有可变位置的字段。但它可以做到。

处理每对中的第一行时,扫描它,找到每个字段名称开头的位置。

awk 'NR%3 == 1 {
        delete fieldpos;
        delete fieldlen;
        lastspace = 1;
        fieldindex = 0;
        for (i = 1; i <= length(); i++) {
            if (substr($0, i, 1) != " ") {
                if (lastspace) {
                    fieldpos[fieldindex] = i;
                    if (fieldindex > 0) {
                        fieldlen[fieldindex-1] = i - fieldpos[fieldindex-1];
                    }
                    fieldindex++;
                }
                lastspace = 0;
            } else {
                lastspace = 1;
            }
        }
    }
    NR%3 == 2 {
        for (i = 0; i < fieldindex; i++) {
            if (i in fieldlen) {
                f = substr($0, fieldpos[i], fieldlen[i]);
            } else { # last field, go to end of line
                f = substr($0, fieldpos[i]);
            }
            gsub(/^ +| +$/, "", f); # trim surrounding spaces
            if (f == "") { f = "X" }
            printf("%s ", f);
        }
    }
    NR%15 == 14 { print "" } # print newline after 5 data blocks
'

答案 1 :(得分:0)

假设您的字段由空白字符而不是制表符分隔,GNU awk的FIELDWITDHS旨在处理这种情况:

/^ZZZZ/ { if (rec!="") print rec; rec="" }
/^[[:upper:]]/ {
    FIELDWIDTHS = ""
    while ( match($0,/\S+\s*/) ) {
        FIELDWIDTHS = (FIELDWIDTHS ? FIELDWIDTHS " " : "") RLENGTH
        $0 = substr($0,RLENGTH+1)
    }
    next
}
NF {
    for (i=1;i<=NF;i++) {
        gsub(/^\s+|\s+$/,"",$i)
        $i = ($i=="" ? "X" : $i)
    }
    rec = (rec=="" ? "" : rec " ") $0
}
END { print rec }

$ awk -f tst.awk file
2129 13242 MUTUAL BOTH NO 3 0 X 3 0 X 2 0 X 5 3 5 3 0 X 3 X

在其他awks中你会使用match()/ substr()。请注意,上面的内容并不完美,它会截断一个字符21293 - 这是因为我不相信你的输入文件是准确的,如果它是你没有告诉我们为什么这个数字长于前面的字符串行或如何处理。