【问题标题】:GAWK - Multiple BEGIN and END sectionsGAWK - 多个 BEGIN 和 END 部分
【发布时间】:2015-08-21 02:35:40
【问题描述】:

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

文件区定宽空格格式化文件

我正在尝试从两个不同的正则表达式匹配的两个不同的行中提取数据,但在 ONE print 语句中返回这两行的数据。

我可以在.awk 文件中使用以下内容来实现这一点,并使用gawk -f 来运行它。第一个 BEGIN 部​​分设置输入文件格式 (FIELDWIDTHs),第二个 BEGIN 我试图使用每个文件的循环来根据提取的数据进行输出。第一个 END 完成内部 BEGIN,第二个匹配外部 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 ($1 == "03") {
            Sales = $15/100;
            SalesA = $17/100;
            SalesB = $26/100;
            SalesC = $20/100;
            SalesD = $22/100;
            JointSales = SalesA - SalesB;
            Turnover = JointSales + SalesB + SalesC + SalesD; }
          else if ( $1 == "06") {
            OtherData = substr($0,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
    }

【问题讨论】:

  • 您希望多个 BEGINEND 块在做什么?你只能得到一个。 BEGIN 在 awk 进程开始时运行,END 在结束时运行。如果您正在寻找在每个已处理文件的开头和结尾运行事物的方法,请查看使用 FNR
  • @EtanReisner 不,您可以拥有任意数量的 BEGIN 和 END 部分,将它们全部放在一个文件中是没有意义的。当您将多个部分脚本存储在多个文件中并且您想要运行一个将所有这些文件串联起来的脚本时,就可以使用它了。我不明白 OP 想要做什么,他需要发布一些示例输入和预期输出,然后才能得到一个解决方案,告诉他如何实现他想要做的任何事情,而不是如何做他需要做的事情.
  • @EdMorton 确实如此。 rici 在下面的评论中纠正了我的误解,是的,现在我考虑到它,我绝对可以看到它在构建更复杂的脚本中的用途。

标签: regex awk gawk


【解决方案1】:

如果您使用的是gawk,那么您很幸运。除了 BEGINEND 块之外,gawk 还实现了 BEGINFILEENDFILE 块,它们可以按照您的需要执行:在处理每个文件之前和之后。请参阅handy gawk programming guide

与所有 awk 实现一样,Gnu awk 允许您拥有多个 BEGINEND 块。在读取第一个文件之前,所有BEGIN 块都按顺序(从第一个到最后一个)运行,在最后一个文件完成后,所有END 块都按相同的从前到最后的顺序运行。由于两种特殊块使用相同的顺序,它们不会“嵌套”。

【讨论】:

  • 谢谢。我将不得不研究 BEGINFILE 和 ENDFILE。
【解决方案2】:

awk 每次运行只允许一个 beginend 动作集(虽然它们可以分布在多个块中,但它们都组合成一个动作集)并且运行包括 all em> 您处理的文件。

如果您还想在每个文件之间进行操作,可以使用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 "   "$0
}

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

您只需使该操作符合您的需要,您当前的“内在”end,然后是您当前的“内在”begin

【讨论】:

  • 为什么要打扰baseNR?为什么不直接检查FNR==1?或者,因为我认为这两个都会丢失空文件,所以将之前的 FILENAME 与当前的 FILENAME(或 ARGIND)进行比较。
  • @Etan,关于第一项的好点,我会调整答案,因为它更容易。但是,由于普通的{} 仅在输入行上运行,我不确定更改后的文件名是否更好——{} 在这种情况下不会运行,是吗? argind 可能会更好,因为它可以检测空文件。
  • 嗯...我不确定您实际上是否可以在线检测空文件。使用ARGIND,您可以检测到您在点击下一个非空文件时跳过了它们(然后运行 ​​X 轮您的中间工作)。虽然如果您关心尾随空文件,也需要检查END
  • (和@EtanReisner):awk 允许多个 BEGIN 和 END 块。从概念上讲,它们是连接在一起的,因此您最终会得到一个初始化/完成序列,但说您只能拥有一个是误导性的。
  • @Etan,是的,也发现了这一点,因此添加了代码。但是,根据 rici 的回答,这对于 GNU awk 来说可能有点过头了,因为它有我不知道的 BEGINFILE 和 ENDFILE。我将把这个答案留在这里,因为它可能对其他不太高级的 awk 仍然有用,但我怀疑 rici 应该是公认的答案。
猜你喜欢
  • 2011-07-23
  • 1970-01-01
  • 2013-09-06
  • 2019-05-18
  • 1970-01-01
  • 2019-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多