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!

4 Answers 4

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?

4
  • Thanks Matt, but i need to support dates from year 0001 to 9999, date command is no good for these years.. Mar 7, 2011 at 19:37
  • I've just noticed another problem with that command - it set my clock to 09/09/2009 :S
    – Majenko
    Mar 7, 2011 at 19:42
  • 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
    Mar 7, 2011 at 19:51
  • Ok, I am editing my answer to have something completely different to what was there...
    – Majenko
    Mar 7, 2011 at 20:00
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.

0

the script on this page does just that

http://www.computing.net/answers/unix/find-the-day-of-week-using-awk/5243.html

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .