Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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;
        }
'
share|improve this question

2 Answers 2

up vote 6 down vote accepted

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.

share|improve this answer
    
BEGIN patterns are executed before any input is read -- unless I use getline.. Thanks for reply. –  user14039 Feb 10 '12 at 22:22

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.

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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.