Search code examples
unixsedksh

Kornshell - How to print blank spaces properly sed and cal


I am currently using this command,

cal $month $year | sed -n '1,2p'
cal $month $year | sed -n '3,$p' |
    sed -n '/'$day'/{s/.*\('$day'.*\)/\1/p; :a; n; p; ba; }'

And it is giving me this output

    March 2014
Su Mo Tu We Th Fr Sa
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

How can I get this output?

    March 2014
Su Mo Tu We Th Fr Sa
       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

FYI: $month $year $day is using the current date. I am trying to avoid using a set number of spaces because if it was a different day then the numbers would not match up with the spaces.

EDIT: For Jonathan Leffler

Thank you! This is getting really close to the output I am looking for. The sample output you posted is exactly what I am looking for but after trying your code. It gave me this instead.

March 2014 Su Mo Tu We Th Fr Sa 2 3 4 5 Q6 7 8 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

How am I able to remove the line with the Q? I assume this is coming from the 2nd s/// you provided

EDIT:

Figure it out, Thank you for your help!


Solution

  • This script works (I think):

    year=2014
    month=3
    day=6
    cal $month $year | sed -n -e '
    1,2p
    3,${/'$day'/{
      s/^\(.*\)\('$day'.*\)/\1Q\2/
      :blanks
      s/^\( *\)[^ Q]/\1 /g
      t blanks
      s/Q//p
      :a
      n
      p
      ba
      }
    }'
    

    Sample output:

         March 2014       
    Su Mo Tu We Th Fr Sa  
                 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
    
    • The first s/// command puts a Q (not part of the output from cal) before the day that you want to keep.
    • The label :blanks, the s/// and the t blanks replace a string of blanks and a non-blank, non-Q with the string of blanks and another blank, zapping all the non-blank characters before the Q.
    • The s/Q//p removes the marker and prints the line.
    • The remainder of the code is the same as before (but spread over multiple lines); it gets the next line of input and prints it repeatedly.