How to detect EOF in awk?

2020-08-13 04:20发布

Is there a way to determine whether the current line is the last line of the input stream?

标签: awk eof
11条回答
Deceive 欺骗
2楼-- · 2020-08-13 04:58

To detect the last line of each file in the argument list the following works nicely:

FNR == 1 || EOF {
  print "last line (" FILENAME "): " $0
}
查看更多
Ridiculous、
3楼-- · 2020-08-13 04:59

gawk implementation has special rule called ENDFILE which will be triggered after processing every file in argument list. This works:

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

more details you can find here>>

查看更多
对你真心纯属浪费
4楼-- · 2020-08-13 05:00

Detecting the EOF is not too reliable when multiple files are on the command line. Detecting the start of the file is more reliable.

To do this, the first file is special and we ignore the FNR==1.

After the first file then FNR==1 becomes the end of the previous file. last_filename always has the filename that you are processing.

Do your file processing after the else.

Do your EOF processing inside the else block, AND in the END block.

   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;}' $*

For multiple file sets, the else block executes at EOF for all but the last file. The last file is executed in the END block.

For single file sets, the else block doesn't get executed, and the END block is executed.

查看更多
叼着烟拽天下
5楼-- · 2020-08-13 05:01

The special END pattern will match only after the end of all input. Note that this pattern can't be combined with any other pattern.

More useful is probably the getline pseudo-function which resets $0 to the next line and return 1, or in case of EOF return 0! Which I think is what you want.

For example:

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

If you are only processing one file, this would be equivalent:

awk 'END { print "Found EOF" }'
查看更多
戒情不戒烟
6楼-- · 2020-08-13 05:01

These are the only sensible ways to do what you want, in order of best to worst:

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
查看更多
唯我独甜
7楼-- · 2020-08-13 05:01

I'm not even sure how to categorize this "solution"

{
    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
}

The cool thing about this hack is that by assigning to $0, all the remaining declarative patterns and actions work, one line delayed. You can't get them to work for the END, even if you put the END on top, but you do have control on the last line and you haven't done anything else to it.

查看更多
登录 后发表回答