【问题标题】:How to detect EOF in awk?如何在awk中检测EOF?
【发布时间】:2009-10-29 21:22:42
【问题描述】:

有没有办法判断当前行是否是输入流的最后一行?

【问题讨论】:

    标签: awk eof


    【解决方案1】:

    特殊的END 模式只会在所有输入结束后匹配。请注意,此模式不能与任何其他模式结合使用。

    更有用的可能是getline 伪函数,它将$0 重置到下一行并返回1,或者在EOF 的情况下返回0!我认为这是您想要的。

    例如:

    awk '{ if(getline == 0) { print "Found EOF"} }'
    

    如果您只处理一个文件,这将是等效的:

    awk 'END { print "Found EOF" }'
    

    【讨论】:

    • 其实,我的第一个例子应该是: awk '{ while(getline == 1) {};打印“找到EOF”}'
    • 没错,忘了提,但如果他是从一堆静态文件中读取,这不太可能,但我想这在很大程度上取决于他的脚本的上下文。
    • 谢谢!如果一个人处理两个文件,那么一个人可以做cmd="cat file2"; while(condition) {if(cmd | getline line2 == 0) break;
    【解决方案2】:

    你有两个选择,都有些混乱。

    1. 将当前每一行的副本存储在一个临时变量中,然后使用 END 块对其进行处理。
    2. 使用系统命令在 BEGIN 块中运行“wc -l | getline”以获取文件中的行数,然后对该值进行计数。

    您可能需要稍微玩一下#2 才能让它运行,但它应该可以工作。自从我做任何 awk 以来已经有一段时间了。

    【讨论】:

    • 呸,我真的很讨厌选项 2。但选项 1 就是这样做的方法。 +1 选项 1。
    • 不!不要使用选项“1”,因为这会浪费资源,也不要使用选项“2”,因为在这种情况下使用 wc 是错误的方式,并且会引入所有 getline 警告。
    • 如果文件要保持相同的行长,您可以使用RECORDS=$(cat myfile | wc -l); awk 'NR == '${RECORDS}' {print "Last Line"}' myfile。嘿,当您选择 AWK 时,您已经超越了优雅。 :)
    【解决方案3】:

    这些是做你想做的事的唯一明智的方法,按从最好到最坏的顺序排列:

    awk 'NR==FNR{max++; next} FNR == max { print "Final line:",$0 }' file file
    
    awk -v max="$(wc -l < file)" 'FNR == max { print "Final line:",$0 }' file
    
    awk 'BEGIN{ while ( (getline dummy < ARGV[1]) > 0) max++; close(ARGV[1])} FNR == max { print "Final line:",$0 }' file
    

    【讨论】:

      【解决方案4】:

      gawk 实现具有称为ENDFILE 的特殊规则,它将在处理参数列表中的每个文件后触发。这有效:

      awk '{line=$0} ENDFILE {print line}' files...
      

      更多详情您可以找到here>>

      【讨论】:

        【解决方案5】:

        当命令行上有多个文件时,检测 EOF 不太可靠。检测文件的开头更可靠。

        为此,第一个文件是特殊的,我们忽略 FNR==1。

        在第一个文件之后,FNR==1 成为前一个文件的结尾。 last_filename 始终包含您正在处理的文件名。

        在 else 之后进行文件处理。

        在 else 块和 END 块中执行 EOF 处理。

           gawk 'BEGIN{last_filename="";} \
              FNR==1{if (last_filename==""){last_filename=FILENAME;} \
              else {print "EOF: "last_filename;last_filename=FILENAME;}} \
              END{print "END: "last_filename;}' $*
        

        对于多个文件集,else 块在 EOF 处对除最后一个文件之外的所有文件执行。最后一个文件在 END 块中执行。

        对于单个文件集,不执行 else 块,而是执行 END 块。

        【讨论】:

          【解决方案6】:

          我什至不知道如何对这个“解决方案”进行分类

          {
              t = lastline
              lastline = $0
              $0 = t
          }
          
          /test/ {
              print "line <" $0 "> had a _test_"
          }
          
          END {
              # now you have "lastline", it can't be processed with the above statements
              # ...but you can work with it here
          }
          

          这个 hack 很酷的一点是,通过分配给 $0,所有剩余的声明性模式和操作都可以工作,延迟一行。即使您将END 放在顶部,您也无法让它们为END 工作,但是您确实可以控制最后一行并且您没有做任何其他事情它。

          【讨论】:

          • 这会只检测awk输入文件列表中最后一个文件的最后一行吗?
          【解决方案7】:

          检测参数列表中每个文件的最后一行 以下效果很好:

          FNR == 1 || EOF {
            print "last line (" FILENAME "): " $0
          }
          

          【讨论】:

            【解决方案8】:

            一种简单的方法是通过中间的sed 脚本运行文件,该脚本在每个非最后一行放置一个 0,在最后一行放置一个 1。

            cat input_file | sed 's/^/0/;$s/0/1/' | awk '{LST=/^1/;$0=substr($0,2)}
            ... your awk script in which you can use LST to check for the
            ... last line.'
            

            【讨论】:

            • 第一个使用 sed 的版本,我发现它确实有效,在我的情况下,我根本不想使用 awk。
            【解决方案9】:

            嗯,awk END 变量告诉您​​何时已经到达 EOF。我猜对你真的没有多大帮助

            【讨论】:

            • 如果有多个文件,END会在最后一个文件的末尾执行一次。
            【解决方案10】:

            你可以试试这个:

            awk 'BEGIN{PFNR=1} FNR==PFNR{PFNR++;next} {print FILENAME,PFNR=2} END{print FILENAME}' file1 file2
            

            【讨论】:

              【解决方案11】:

              A portable solution is provided in the gawk user manual,虽然在另一个答案中提到,gawk 本身有 BEGINFILE 和 ENDFILE。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2010-11-28
                • 2018-01-01
                • 1970-01-01
                • 2012-03-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多