using awk to make exact matches

0

i'm just wondering how can we use awk to do exact matches.

for eg

$ cal 09 09 2009
   September 2009
Su Mo Tu We Th Fr Sa
   1  2  3  4  5
6  7  8  9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30



$ cal 09 09 2009 | awk '{day="9"; col=index($0,day); print col }'
17
0
0
11
20
0
8
0

As you can see the above command outputs the index number of all the lines that contain the string/number "9", is there a way to make awk output index number in only the 4th line of cal output above.??? may be an even more elegant solution?

I'm using awk to get the day name using the cal command. here's the whole line of code:

     $ dayOfWeek=$(cal $day $month $year | awk '{day='$day'; split("Sunday Monday Tuesday Wednesday Thursday Friday Saturday", array); column=index($o,day); dow=int((column+2)/3); print array[dow]}')

The problem with the above code is that if multiple matches are found then i get multiple results, whereas i want it to output only one result.

Thanks!

Jasdeep Singh

Posted 2011-03-07T19:23:46.060

Reputation: 101

Answers

0

You could grep the output of cal to only give you the one line:

$ cal 09 09 2009 | grep -E '(^9 | 9 | 9$)' | awk ...

The grep matches one of:

  • A 9 followed by a space at the start of the line
  • A 9 surrounded by spaces
  • A space followed by a 9 at the end of the line.

How's that work for you?

Majenko

Posted 2011-03-07T19:23:46.060

Reputation: 29 007

Thanks Matt, but i need to support dates from year 0001 to 9999, date command is no good for these years.. – Jasdeep Singh – 2011-03-07T19:37:51.843

I've just noticed another problem with that command - it set my clock to 09/09/2009 :S – Majenko – 2011-03-07T19:42:40.857

Well, I'm getting stumped. I was thinking of passing it through grep first but that wouldn't work for the first / last numbers on the line. Or would it? Hang on... – Majenko – 2011-03-07T19:51:35.073

Ok, I am editing my answer to have something completely different to what was there... – Majenko – 2011-03-07T20:00:06.247

0

I would do this with something like

dayOfWeek="$(cal $month $year |
             awk -v day=$day \
                'BEGIN {split("Sunday Monday Tuesday Wednesday Thursday Friday Saturday", days)}
                 NR > 2 {for (i = 1; i <= NF; i++) {if ($i == day) {print days[i]}}}')"

Here, BEGIN executes at the start to set up the days array; the other pattern triggers on lines 2 and up (skipping the header), steps through the columns until it finds day, and then uses the column number to look up the weekday. $ in awk is the field reference operator; just as $1 is the first field, $n is the field numbered by the value of n. I'm also passing $day from the shell to the script with the assignment at the start of the awk line. NR is the record number (line number); NF is the number of fields on the line. (You can set RS and FS, respectively, to change what separates records and fields, respectively.)

(The backslash-newlines and the newline after the pipe | are just for clarity and to make it not scroll too much.)

This time it's tested.

geekosaur

Posted 2011-03-07T19:23:46.060

Reputation: 10 195

0

Mohamed

Posted 2011-03-07T19:23:46.060

Reputation: 1

0

Give this a try:

cal 09 2009 | awk -v "num=9" '
    BEGIN {
        OFS="\t";
        day=" ?[^0-9]" num "([^0-9]|$)"
    }
    NR==2 {dow = $0}
    $0 ~ day {
        col=match(" " $0, day);
        print $0, col, substr(dow,col,2)
    }'

All on one line:

cal 09 2009 | awk -v "num=9" 'BEGIN {OFS="\t"; day=" ?[^0-9]" num "([^0-9]|$)"} NR==2 {dow = $0} $0 ~ day {col=match(" " $0, day); print $0, col, substr(dow,col,2) }'

Demo:

$ for i in {1..30}; do cal 09 2009 | awk -v "num=$i" 'BEGIN {OFS="\t"; day=" ?[^0-9]" num "([^0-9]|$)"} NR==2 {dow = $0} $0 ~ day {col=match(" " $0, day); print $0, num, col, substr(dow,col,2) }'; done
       1  2  3  4  5    1       7       Tu
       1  2  3  4  5    2       10      We
       1  2  3  4  5    3       13      Th
       1  2  3  4  5    4       16      Fr
       1  2  3  4  5    5       19      Sa
 6  7  8  9 10 11 12    6       1       Su
 6  7  8  9 10 11 12    7       4       Mo
 6  7  8  9 10 11 12    8       7       Tu
 6  7  8  9 10 11 12    9       10      We
 6  7  8  9 10 11 12    10      13      Th
 6  7  8  9 10 11 12    11      16      Fr
 6  7  8  9 10 11 12    12      19      Sa
13 14 15 16 17 18 19    14      4       Mo
13 14 15 16 17 18 19    15      7       Tu
13 14 15 16 17 18 19    16      10      We
13 14 15 16 17 18 19    17      13      Th
13 14 15 16 17 18 19    18      16      Fr
13 14 15 16 17 18 19    19      19      Sa
20 21 22 23 24 25 26    21      4       Mo
20 21 22 23 24 25 26    22      7       Tu
20 21 22 23 24 25 26    23      10      We
20 21 22 23 24 25 26    24      13      Th
20 21 22 23 24 25 26    25      16      Fr
20 21 22 23 24 25 26    26      19      Sa
27 28 29 30             28      4       Mo
27 28 29 30             29      7       Tu
27 28 29 30             30      10      We

Here is an improvement on the script that Mohamed linked to:

cal 09 2009 | awk -v "d=9" 'NR==2 {split($0, dow)} NR == 3 {print $0, d, dow[7 - ($NF + 35 - d) % 7]}'

There's no need for head, tail or a bunch of if statements.

Paused until further notice.

Posted 2011-03-07T19:23:46.060

Reputation: 86 075