[conspire] CABAL and you: a winter's tale

Rick Moen rick at linuxmafia.com
Tue Jan 24 00:32:52 PST 2017


Earlier this month, I wrote:

> Hey, it's about to be the second Saturday of the month on
> 
> :r! cal | sed -n 4p | awk '{print $7}'
> 14
> 
> ...the 14th of this very month -- thus, tomorrow.

What I posted is indeed a correct shell snippet -- but only for
Saturdays.

$ cal
    January 2017    
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 31            
$
                   
My shell snippet grabbed line four...

$ cal | sed -n 4p
 8  9 10 11 12 13 14
$

...and got the seventh field.

$ cal | sed -n 4p | awk '{print $7}'
14
$

This works for Saturdays because, irrespective of what day of the week
starts a month, the first week will always include a Saturday, hence
that 1st Saturday will always be on line 3, hence the month's 2nd Saturday 
will always be on the next line, line 4.

But consider 2nd Mondays.  Sure, in Jan. 2017, that was on line 4, but
look at February:

$ cal February 2017
   February 2017    
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            
$
                    
Because of the partial first week, the month's 2nd Monday appears on
line 5 of cal's output, not 4.  So, my snippet works for Saturdays, but
not reliably for any other day of the week.



Casting about for an efficient solution, I stumbled upon ncal, which 
flips cal's output:

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

2nd Monday?  No problem.  It'll always be item 3 on ncal's 'Mo' line,
aka line 2.

$ ncal February 2017 | grep ^Mo | awk '{print $3}'
13
$ 


Want something even faster and lighter than awk?  Use cut, though you
have to 'squeeze' space characters using tr or similar, because
otherwise cut makes dumb assumptions about what consecutive spaces mean.

$ ncal February 2017 | grep ^Mo | tr -s " " | cut -d ' ' -f 3
13
$

There, a general recipe using the fastest, lightest tools around.





More information about the conspire mailing list