GAWK - 多个 BEGIN 和 END 部分

GAWK - Multiple BEGIN and END sections

我正在尝试使用 gawk 处理一堆文件以提取数据。

文件区固定宽度space格式化文件

我正在尝试从由两个不同的正则表达式匹配的两个不同的行中提取数据,但是 return 在一个打印语句中从这两行中提取数据。

我可以通过 .awk 文件中的以下内容实现这一点,并使用 gawk -f 到 运行 它。第一个 BEGIN 部​​分设置输入文件格式(FIELDWIDTHs),第二个 BEGIN 我试图对每个文件使用一个循环以根据提取的数据输出。第一个 END 完成内部 BEGIN,第二个 END 匹配外部 BEGIN。

但是我一次只能将它应用到一个文件,因为如果我应用到一堆文件(如 gawk -f regex.awk km*.txt 中,我只能得到最后一个文件的输出。

我能否为每个文件输入获得一行输出,而不必求助于循环遍历输入文件的脚本文件并每次都 运行 调用 awk 脚本。

谢谢

    BEGIN{
    OFS=","; FIELDWIDTHS ="2 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12";
                printf("Date,  Turnover, SalesA, SalesB, SalesC, SalesD, Other Data\n");
                }

    BEGIN{      Sales = 0;
                SalesA = 0;
                SalesB = 0;
                SalesC = 0;
                SalesD = 0;
                JointSales = 0;
                Turnover = 0;
                OtherData = 0;}

    /^03/ || /^06/ {

          if ( == "03") {
            Sales = /100;
            SalesA = /100;
            SalesB = /100;
            SalesC = /100;
            SalesD = /100;
            JointSales = SalesA - SalesB;
            Turnover = JointSales + SalesB + SalesC + SalesD; }
          else if (  == "06") {
            OtherData = substr([=10=],183,12)/100; }

    #     printf("%s, %10.2f, %10.2f, %10.2f, %10.2f, %10.2f, %10.2f\n",  getDate(FILENAME), Sales, JointSales, SalesB, SalesC, SalesD, OtherData ) 
    }

    END{printf("%s, %10.2f, %10.2f, %10.2f, %10.2f, %10.2f, %10.2f\n",  getDate(FILENAME), Sales, JointSales, SalesB, SalesC, SalesD, OtherData ) }

    END {}


    function getDate(str)
    {   date = substr(str,3,6);
        year = substr(date,1,2);
        month= substr(date,3,2);
        day=substr(date,5,2);
        odate=(day"/"month"/"year);
       return odate
    }

awk 只允许每个 运行 设置一个 beginend 动作(虽然它们可以分布在多个块中,但它们都组合成一个动作set) 和 运行 包含您处理的 所有 个文件。

如果你还想在每个文件之间做一些事情,可以使用ARGIND变量保存当前参数的索引(从零开始) .您只需要维护最后一个参数索引(最初为零),如果 actual 参数索引不同,则执行您的特殊操作并更新最后一个索引。

对于空文件(没有代码 运行),当前参数索引可能比上一个高一个以上,因此您可能需要 循环, 递增最后一个索引,直到它到达当前索引。

例如,让我们打印每个文件的行,但在之前、之中和之后使用特殊标记。使用文件 a.in:

xyzzy
plugh

和一个什么都不包含的b.in文件,你可以使用下面的脚本demo.awk:

function middleCheck() {
    while (lastArgInd != ARGIND) {
        print "MIDDLE after "lastArgInd":"ARGV[lastArgInd]
        lastArgInd++
    }
}

BEGIN { print "BEGIN"
        lastArgInd = 1
}

{       middleCheck()
        print "   "[=11=]
}

END {   middleCheck()
        print "END"
}

在每个文件之间执行一个操作:

pax> vi demo.awk ; awk -f demo.awk b.in a.in a.in b.in a.in b.in b.in
BEGIN
MIDDLE after 1:b.in
   xyzzy
   plugh
MIDDLE after 2:a.in
   xyzzy
   plugh
MIDDLE after 3:a.in
MIDDLE after 4:b.in
   xyzzy
   plugh
MIDDLE after 5:a.in
MIDDLE after 6:b.in
END

您只需要使该操作符合您的需要,您当前的 "inner" end 后跟您当前的 "inner" begin.

如果您正在使用 gawk,那您就走运了。除了 BEGINEND 块之外,gawk 还实现了 BEGINFILEENDFILE 块,它们按照您的需要执行:在处理每个文件之前和之后。见 handy gawk programming guide.

与所有 awk 实现一样,Gnu awk 允许您拥有多个 BEGINEND 块。在读取第一个文件之前,所有 BEGIN 个块都是 运行 顺序(从前到后),所有 END 个块都是 运行 相同的从头到尾的顺序最后一个文件完成后。由于两种类型的特殊块使用相同的顺序,因此它们不会 "nest".