1

In the following snippet, $2 in awk is returning empty. What am I doing wrong? I am trying to find the difference between MAX and MIN.

#!/bin/ksh
if [ $# -ne 1 ]; then
        echo "Usage: sh `basename ${0}` filename";
        exit 1;
fi
if [ ! -s ${1} ]; then
        echo "file doesn't exist or is empty";
        exit 1;
fi
sed -e '/^$/d' -e '/^#/d' ${1} |
awk  -F'=' '
        BEGIN {
                MIN=$2; MAX=$2; print MIN;
        }
        {
                if ( $2 > MAX )
                {
                        MAX = $2;
                }
                else if ( $2 < MIN )
                {
                        MIN = $2;
                }
        }
        END {
                DIFF=MAX-MIN; print "DIFF:" DIFF;
        }
'

However, this is working fine. Why doesn't $2 work in the BEGIN section?

#!/bin/ksh
if [ $# -ne 1 ]; then
        echo "Usage: sh `basename ${0}` filename";
        exit 1;
fi
if [ ! -s ${1} ]; then
        echo "file doesn't exist or is empty";
        exit 1;
fi
sed -e '/^$/d' -e '/^#/d' ${1} |
awk -F'=' '
        {
                if ( MAX == "" || MIN == "" )
                {
                        MAX = MIN = $2;
                }
                else
                {
                        if ( $2 > MAX )
                        {
                                MAX = $2;
                        }
                        else if ( $2 < MIN )
                        {
                                MIN = $2;
                        }
                }
        }
        END {
                DIFF=MAX-MIN; print "DIFF:" DIFF;
        }
'
6

BEGIN patterns are executed before any input is read, so consequently none of the variables that refer to input, like NR, fields like $0..., will be defined in any of the BEGIN blocks. Your second approach is correct and much better.¹ From the POSIX awk spec (emphasis mine):

The awk utility shall recognize two special patterns, BEGIN and END. Each BEGIN pattern shall be matched once and its associated action executed before the first record of input is read ...

¹ Just a side note, it's also good because it doesn't make assumptions about the minimum or maximum being bounded by a particular value like 0, something many one-liners one finds on the internet assume.

  • BEGIN patterns are executed before any input is read -- unless I use getline.. Thanks for reply. – user14039 Feb 10 '12 at 22:22
1

If you want to execute a command on the first line of input text, you should use NR==1 pattern, not BEGIN.

awk  -F'=' '
    NR==1 {
            MIN=$2; MAX=$2; print MIN;
    }
    NR>1 {
            if ( $2 > MAX )
            {
                    MAX = $2;
            }
...

As stated by @jw013, BEGIN pattern is for actions to execute before you read the first line.

  • You could avoid the NR>1 test by ending the first block with next. – dubiousjim Apr 19 '12 at 19:27

Your Answer

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