awk: how to "nextfile" in ENDFILE?

Viewed 165

refer to "The GNU Awk User's Guide"

The next statement (see section The next Statement) is not allowed inside either a BEGINFILE or an ENDFILE rule. The nextfile statement is allowed only inside a BEGINFILE rule, not inside an ENDFILE rule.

I have tested "nextfile" in BEGINFILE: Even if nextfile is written in BEGINFILE, the corresponding file in ENDFILE will be executed

I wonder how can I skip the "file" that "nextfile" in BEGINFILE

2 Answers

If your question is "can we use nextfile inside ENDFILE section" Then short answer is no, we can't use it.

Here is an example:

  • Use of nextfile in BEGINFILE section: Let's say we have 2 Input_files named file1 and file2. Let us run nextfile inside BEGINFILE rule.

awk 'BEGINFILE{print FILENAME;nextfile} 1' file1 file2
file1
file2

We could see its printing Input_file names in it and NOT printing the contents of files, means its working fine.

  • Use of nextfile inside ENDFILE block: Now lets run nextfile inside ENDFILE section and see what happens.

awk '1;ENDFILE{nextfile;print "bla bla"}' file1 file2
awk: cmd. line:1: error: `nextfile' used in ENDFILE action

It gives an error as you see above. Why this is happening, because ENDFILE OR END blocks always get executed after all the records of Input_file(s) are done with executing, so in case you want to jump to next Input_file then you could either use it in BEGINFILE OR BEGIN section OR use it in main block of your code in case you want to match specific condition and then jump to next Input_file.



How to skip ENDFILE section for a specific Input_file: If you have an ENDFILE statement then on each Input_file's record reading, then to skip a specific Input_file we could use condition like this:

awk '1;ENDFILE{if(FILENAME!="file2"){print FILENAME}}' file1 file2

Output will be as follows.

bla bla bla file1 contents here.....
file1
bla bnla bla file2 contents here....

Basically its print contents of Input_file1 and Input_file2 but because a condition is mentioned in ENDFILE block its NOT printing file2 name in output, hence prevented a statements from execution in ENDFILE block here.



Ideal use of nextfile in BEGINFILE block: If we use nextfile inside BEGINFILE block then it will for sure NOT going to print any of the records of that specific Input_file, why because BEGINFILE block's statements gets executed before reading records from Input_file when we mention nextfile it will NOT start reading records process and will simply jump to next Input_file.

So when to use nextfile in BEGINFILE block?: IMHO one of the BEST use case will be when we want to process multiple Input_file(s) and want to deal with headers for each Input_file(eg--> print only header OR a message for specific file and DO NOT process records of that Input_file). OR 2nd case I could think of if any processing you need to do before executing the records of that Input_file.

If you read the GNU awk manual, then it states this about nextfile:

In gawk, execution of nextfile causes additional things to happen: any ENDFILE rules are executed if gawk is not currently in an END or BEGINFILE rule, ARGIND is incremented, and any BEGINFILE rules are executed.

With gawk, nextfile is useful inside a BEGINFILE rule to skip over a file that would otherwise cause gawk to exit with a fatal error. In this case, ENDFILE rules are not executed.

source: GNU awk manual: nextfile statement

So, what does this mean?

  • ENDFILE is executed if nextfile is in a normal pattern-action pair (pattern { action })

    $ awk '{nextfile}1;ENDFILE{print "processing ENDFILE"}' /dev/random
    processing ENDFILE
    
  • ENDFILE is executed if nextfile is in a BEGINFILE-block (BEGINFILE { action })

    $ awk 'BEGINFILE{print "processing BEGINFILE with error", ERRNO; nextfile}1
           ENDFILE{print "processing ENDFILE"}' /dev/random
    processing BEGINFILE with error 
    processing ENDFILE
    
  • ENDFILE is not executed if nextfile is in a BEGINFILE-block and an error occurred (BEGINFILE { action })

    $ touch foo; chmod -r foo
    $ awk 'BEGINFILE{print "processing BEGINFILE with error", ERRNO; nextfile}1
            ENDFILE{print "processing ENDFILE"}' foo
    processing BEGINFILE with error Permission denied
    

How can we skip ENDFILE using nextfile?

The answer is to fake an error. By assigning anything to the Gnu variable ERRNO, you will skip the ENDFILE block

$ awk 'BEGINFILE{ERRNO=1; print "processing BEGINFILE with error", ERRNO; nextfile}1 
       ENDFILE{print "processing ENDFILE"}' /dev/random
processing BEGINFILE with error 1
Related