1

[GNU awk v4.2.1 on Archlinux]

Suppressing awk's default print action to stdout from cli is easy and well documented on UL, e.g. here. Doing so from a script gives me headaches. Here's the toy script:

#!/usr/bin/awk -f
BEGIN {FS=","} 
FNR > 1          # skip header
{   
    if ( $1 == $2 ) {
        if ( NR == 4 ) {
            printf("*** Print NR=4 ok. \n")
        } else {
            print > "/dev/null"  # print nothing
        }
    } else {
        printf("=== Fields 1 and 2 not equal (NR=%s). \n",NR)
    }
}

and toy data:

col1 col2
1,3
2,2
aa,aa
3.01,-353.01
4.1,4.1
101,101
hello, hello
asd,koi0

along with expected / desired output:

=== Fields 1 and 2 not equal (NR=2). 
*** Print NR=4 ok. 
=== Fields 1 and 2 not equal (NR=5).
=== Fields 1 and 2 not equal (NR=8).
=== Fields 1 and 2 not equal (NR=9).

Instead I get:

=== Fields 1 and 2 not equal (NR=1). 
1,3
=== Fields 1 and 2 not equal (NR=2). 
2,2
aa,aa
*** Print NR=4 ok. 
3.01,-353.01
=== Fields 1 and 2 not equal (NR=5). 
4.1,4.1
101,101
hello, hello
=== Fields 1 and 2 not equal (NR=8). 
asd,koi0
=== Fields 1 and 2 not equal (NR=9). 

To suppress output to stdout, I tried using: getline, {}, next, printf("") and even the outlandish ORS=""; print ""; ORS="\n" instead of print > "/dev/null". I am obviously doing something very wrong in that frigging script and can not find what ...

3

The only error is

FNR > 1          # skip header
{ 

which should be

FNR > 1 {        # skip header

A code block with a condition must start on the same line as the condition.

What your original script actually does is first

FNR > 1

This prints all lines from line two onwards (the default action when a condition does not have an associated code block is to print the current record if the condition is true, as if the block had been { print }).

Then it applies the block following that to each line (since that block does not have an associated condition).

This is not a peculiarity of GNU awk. All awk implementations should act like this.


As for the other bits of the script:

    } else {
        print > "/dev/null"  # print nothing
    }

This could be deleted, leaving

#!/usr/bin/awk -f

BEGIN { FS = "," } 

FNR > 1 {   
    if ( $1 == $2 ) {
        if ( NR == 4 )
            printf("*** Print NR=4 ok.\n")
    } else
        printf("=== Fields 1 and 2 not equal (NR=%s).\n", NR)
}

or,

#!/usr/bin/awk -f

BEGIN { FS = "," } 

FNR == 1 { next }

$1 == $2 && NR == 4 { printf("*** Print NR=4 ok.\n") }
$1 != $2            { printf("=== Fields 1 and 2 not equal (NR=%s).\n", NR) }
  • +1 crystal clear explanation. I did not know that awk script syntax required the opening bracket of a conditional block to be on the same line as the conditional expression. That's what awk on cli does not reveal to the novice script writer. Thanks. – Cbhihe Mar 14 at 7:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.