Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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!

share|improve this question

4 Answers 4

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?

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

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.

share|improve this answer

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.

share|improve this answer

Your Answer

 
discard

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.