0
Month Sales
January 20
February 30
March 43
February 34
January 12
June 89
May 97
June 60
July 23
August 13
August 45
October 56
October 45
November 34

Write an awk script to find the months with no sales.

Do we need to have an array containing the names of all the months and do we have to check it with array[$1]? I tried that but I keep messing up the syntax.

echo 'January 
February
March
April
May
June
July
August
September
October
November
December' | 
awk '
BEGIN{ flag=0;}
{arr[month++]=$0}
{ 
    sales[$1]+=$2;
}
END
{
    for(month in arr)
    {
        if(month in sales)
            flag=1;

        if(flag==0) 
            print month;
    }
}'

This is what I've tried so far. I keep getting an error saying:

awk: cmd. line:8: END blocks must have an action part
  • maybe awk '$2==0' inputfileName? or awk 'NF==1' inputfileName – αғsнιη Sep 1 at 10:57
  • 2
    Is this a homework assignment? Please show us your efforts. There seem to me to be at least 2 ways to approach it (1) create an array indexed by months in a BEGIN block, assign values to the elements, then iterate over the array in an END block and print any whose value is zero (2) create the array on the fly, then iterate over all the months in an END block and print any missing indices. – steeldriver Sep 1 at 12:47
0

I think I can see where you're going with this - but it can be simplified quite a lot

  • pipe in the names of the 12 months via standard input and use them as indices of an array

  • read the file of monthly sales, deleting each month as we see it

  • print whatever months remain at the end

The trick is to use - as a special filename to tell awk which order to read the standard input and the file, and NR==FNR as a test for whether we are reading stdin:

printf '%s\n' January February March April May \
    June July August September October November December | awk '
      NR==FNR {sales[$1]; next} {delete sales[$1]} END {for(m in sales) print m}
    ' - sales.txt
December
September
April

Note that you don't need to assign values to the array elements - just assigning indices is sufficient to define the array.

Alternatively, you could define the array in a BEGIN block:

awk '
  BEGIN {
    sales["January"]; sales["February"]; sales["March"]; 
    sales["April"]; sales["May"]; sales["June"]; 
    sales["July"]; sales["August"]; sales["September"]; 
    sales["October"]; sales["November"]; sales["December"];
  } 
  {delete sales[$1]}
  END {
    for(m in sales) print m
  }' sales.txt

A couple of alternative KISS approaches:

(1) create an array indexed by months in a BEGIN block, assign values to the elements, then iterate over the array in an END block and print any whose value is zero

awk '
  BEGIN {
    sales["January"]; sales["February"]; sales["March"]; 
    sales["April"]; sales["May"]; sales["June"]; 
    sales["July"]; sales["August"]; sales["September"]; 
    sales["October"]; sales["November"]; sales["December"];
  } 
  NR > 1 {
    sales[$1] += $2;
  }
  END {
    for (m in sales) {
      if (sales[m] == 0) print m;
    }
  }
' sales.txt

or (2) create the array on the fly from the sales.txt file, then iterate over all the months in an END block and print any missing indices

awk '
  NR > 1 {
    sales[$1] += $2
  } 
  END {
    n = split("January February March April May June July August September October November December", months); 
    for (i=1;i<=n;i++) {
      if (!(months[i] in sales)) print months[i]
    }
  }
' sales.txt

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.