Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

Even more fun with cal and GeekTool UNIX
Some hints ago, it was shown the use of the cal shell command to generate a calendar of the current month. Another more recent hint (in the comments) talked about this utility in conjunction with GeekTool to have a desktop calendar, a simple solution that I enjoyed a lot.

But something wasn't perfect for me, so I did a little study on the subject to solve some problems and enhance the display of cal. I know that I could have used other programs or AppleScript and lived happily, but I wanted to use only shell scripting (so geeky ... but fun). Read the rest of the hint for my efforts.

All examples below are a one single line of code, and you should be able to copy and paste them directly into your Terminal or a GeekTool script action. Let's start:

First day of week.
What if first day of week is Monday, not Sunday? cal has no flag to solve the problem, so I did a little scripting and solved it this way:
cal | awk '{ print " "$0; getline; print " Mo Tu We Th Fr Sa Su"; \
getline; if (substr($0,1,2) == " 1") print "                    1 "; \
do { prevline=$0; if (getline == 0) exit; print " " \
substr(prevline,4,17) " " substr($0,1,2) " "; } while (1) }'
Here is the result:
      June 2004
 Mo Tu We Th Fr Sa Su
     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  
Mark current day
Next, it would be handy to display the current day number at the left of the month's name and in the calendar itself. Here it is:
echo `date "+%d %B %Y"` | awk \
'{ print substr("          ",1,(21-length($0))/2) $0; }'; \
cal | awk '{ getline; print " Mo Tu We Th Fr Sa Su"; getline; \
if (substr($0,1,2) == " 1")  print "                    1 "; \
do { prevline=$0; if (getline == 0) exit; print " "\
substr(prevline,4,17) " " substr($0,1,2) " "; } while (1) }' | \
awk -v cday=`date "+%d"` '{ fill=(int(cday)>9?"":" ");    \
a=$0; sub(" "fill int(cday)" ","*"fill int(cday)"*",a); print  a }'\
Here is the result:
    25 June 2004
 Mo Tu We Th Fr Sa Su
     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  
Localization
At last, I want the calendar localized without changing the locale of the shell (it seems that locale is not supported in Darwin. Hints?). Let's localize it in Italian:
echo `date "+%d/%m/%Y"` | \
awk '{ split("Gennaio/Febbraio/Marzo/Aprile/Maggio/Giugno/Luglio/Agosto/\
Settembre/Ottobre/Novembre/Dicembre",arr,"/"); \
split($0,arg,"/"); a=" " int(arg[1]) " " arr[int(arg[2])] " " arg[3]; \
print substr("          ",1,(21-length(a))/2) a; }' ; cal | \
awk '{ getline; print " Lu Ma Me Gi Ve Sa Do"; getline; \
if (substr($0,1,2) == " 1")  print "                    1 "; \
do { prevline=$0; if (getline == 0) exit; print " " substr(prevline,4,17) \
" " substr($0,1,2) " "; } while (1) }' | awk -v cday=`date "+%d"` \
'{ fill=(int(cday)>9?"":" ");     a=$0; sub(" "fill int(cday)" ",\
"*"fill int(cday)"*",a); print  a }'
Here is the result:
    25 Giugno 2004
 Lu Ma Me Gi Ve Sa Do
     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  
By simply changing the "months" string, you can localize this script for any language. You can also change the day delimiter (*) (in the section "*"fill int(cday)"*" to whatever you like -- I got a better display with ""). I presume some parts of my script could be written in a smarter way, by the way it works. Hope this can be useful for some of you.

[robg adds: I broke the lines with backslashes, and tested each example in the Terminal -- they all worked fine. If they don't work in Geektool, you'll have to remove the line breaks and backslashes prior to pasting...]
    •    
  • Currently 2.56 / 5
  • 1
  • 2
  • 3
  • 4
  • 5
  (9 votes cast)
 
[60,564 views]  

Even more fun with cal and GeekTool | 37 comments | Create New Account
Click here to return to the 'Even more fun with cal and GeekTool' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Even more fun with cal and GeekTool
Authored by: ennisdb on Jun 28, '04 01:35:08PM

Very nice. I've been using GeekTool since the original post. I'll add the *day* highlighting later. Any advice on displaying selected months? That is, it would be nice to display, the previous, current, and next month. Or perhaps, the next three months. Obviously its easy to display all twelve months, but most often one only needs a few months.



[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: groundswells on Jun 28, '04 02:15:55PM

I don't have my Mac out right now, but I assume it works the same as in most unix distros 'cal 7 2004' would display july 2004 or 'cal 12 2004' would display decembers. Maybe I am missing the question.



[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: Anonymous on Jun 28, '04 03:37:37PM

No, he's looking to know how to show *multiple* selected months, i.e., "show me June, July, and August." I don't know if you can just go cal 4 5 6 2004, but I doubt it ... although, posting this from a Windows box, I have no way to check ...



[ Reply to This | # ]
'cal 4 5 6 2004' doesn't work
Authored by: the_webmaestro on Jun 28, '04 04:49:53PM

I don't have a solution, but I know that doesn't work...

---
Father of Jeremy Logan Leeds



[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: da5idonimac on Jun 28, '04 04:57:24PM

simple. just make multiple windows in geektool, one for each desired month and enter 'cal 6 2004', 'cal 7 2004' and 'cal 8 2004' as commands for the respective months (windows).
now you an drag around the windows and arrange them the way wou want them...
i assume someone smart can create the appropriate shell-commands to create the desired months automagically.



[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: ennisdb on Jun 28, '04 05:12:38PM

I had a feeling I wasn't being clear enough. Obviously I can go into GeekTool and change the month range whenever I want. It would be sort of silly to have "cal 7 2004; cal 8 2004; cal 9 2004" unless you only wanted those specific months year round. Conveniently, "cal" alone assumes the current month and year, but there is not an obvious way to output "cal n-1; cal n; cal n+1" where n is the current month which can presumably be obtained from the OS. I'd like to display last-, this-, and next-month without having to hard code "this" month. Is that more clear?



[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: ennisdb on Jun 28, '04 05:14:46PM

For clarity, and in response to the earlier points I should add that:

cal 7 2004; cal 8 2004; cal 9 2004;

Provides a suitably formatted output for multiple months...IF you only want those hard coded months.



[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: dILVISH on Jun 28, '04 06:38:56PM
Okay, this is crude and awful, but it seems to work. Any better solutions welcome! Anyway, after seeing the post this morning I got all excited, but I wanted to see previous and next month as well. I ended up with a small shell script.


#!/bin/sh

month=`date +%m`
year=`date +%Y`

nextMonth=$(($month+1))
lastMonth=$(($month-1))

if [[ $nextMonth -gt 12 ]]
then
	nextMonth=1
	year=$(($year+1))
fi

if [[ $lastMonth -eq 0 ]]
then
	lastMonth=12
	year=$(($year-1))
fi

cal $lastMonth $year
cal $month $year
cal $nextMonth $year



[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: dILVISH on Jul 05, '04 09:19:51PM
Well, no one volunteered to improve upon my code, which is too bad. But I *did* make a couple of small improvements that are worth mentioning. This will display the previous, current and next month vertically, with the current date highlighted with parenthesis.

I'm pretty sure the original post from wallybear would have had a problem highlighting the first or last days of the week, so that's been fixed here. I did NOT include the change so the week starts on Monday, I like Sunday.

Here is the code:


#!/bin/zsh

month=`date +%m`
year=`date +%Y`

nextMonth=$(($month+1))
lastMonth=$(($month-1))

if [[ $nextMonth -gt 12 ]]
then
        nextMonth=1
        year=$(($year+1))
fi

if [[ $lastMonth -eq 0 ]]
then
        lastMonth=12
        year=$(($year-1))
fi

cal $lastMonth $year | awk '{ print $0; while (getline != 0 ) { print " "$0 }}'
cal | awk -v cday=`date "+%d"` '{ fill=(int(cday)>9?"":" "); print " "$0; getline; print " "$0; while (getline != 0) {a=" "$0" "; sub(" "fill int(cday)" ",fill "(" int(cday)")", a); print a }}'
cal $nextMonth $year | awk '{ print $0; while (getline != 0 ) { print " "$0 }}'
and here is the output:

     June 2004
  S  M Tu  W Th  F  S
        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
 
      July 2004
  S  M Tu  W Th  F  S
              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 
  
    August 2004
  S  M Tu  W Th  F  S
  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

Last word on the subject, I promise!

[ Reply to This | # ]

Even more fun with cal and GeekTool
Authored by: wallybear on Jul 07, '04 04:56:32AM

No, my code has no problem marking first or last day of the week, as I added a space before and after each line, in order to make the replace string working everywhere.
Just give it a try...



[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: mrchaotica on Jul 09, '04 01:09:56AM
there's one serious issue with your script: When the month is december or january, it wil display the wrong year, since you only calculate it once. If it's december, you have to call only the next month with "year + 1", and if it's january, you have to call only the previous month with "year - 1" Here's the fix:

#!/bin/zsh

month=`date +%m`
year=`date +%Y`

nextMonth=$(($month+1))
lastMonth=$(($month-1))

if [[ $month -eq 1 ]]
then
        lastMonth=12
        cal $lastMonth $(($year-1)) | awk '{ print $0; while (getline != 0 ) { print " "$0 }}'
else
        cal $lastMonth $year | awk '{ print $0; while (getline != 0 ) { print " "$0 }}'
fi

cal | awk -v cday=`date "+%d"` '{ fill=(int(cday)>9?"":" "); print " "$0; getline; print " "$0; while (getline != 0) {a=" "$0" "; sub(" "fill int(cday)" ",fill "(" int(cday)")", a); print a }}'

if [[ $month -eq 12 ]]
then
        nextMonth=1
        cal $nextMonth $(($year+1)) | awk '{ print $0; while (getline != 0 ) { print " "$0 }}'
else
        cal $nextMonth $year | awk '{ print $0; while (getline != 0 ) { print " "$0 }}'
fi


[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: DavidRavenMoon on Jun 29, '04 08:30:27AM
Easier than all this, but not as geeky, is Menu Calender

You can switch months, and it has iCal support.

[ Reply to This | # ]

Even more fun with cal and GeekTool
Authored by: guybrush on Jun 28, '04 05:17:34PM

gcal has more options and has localizations :)

http://www.gnu.org/software/gcal/gcal.html

its very old, but if you google for it you can find a copy.
and it compiles fine on osx



[ Reply to This | # ]
Even more fun with cal and GeekTool - My rendition
Authored by: josephaw on Jun 28, '04 07:12:30PM
This is my code for cal:
date "+   %a %b %d, %Y%n      %I:%m %p"; cal | tail -n 7
Doesn't have the day marked yet, but I wanted to see the date and time in my cal window on the desktop.

[ Reply to This | # ]
Even more fun with cal and GeekTool - My rendition
Authored by: trel1023 on Jun 29, '04 01:44:28AM
date "+   %a %b %d, %Y%n      %I:%m %p"; cal | tail -n 7
should definitely be
date "+   %a %b %d, %Y%n      %I:%M %p"; cal | tail -n 7
your minutes were always showing 06 (which is of course, the month)

[ Reply to This | # ]
better highlight
Authored by: mzs on Jun 29, '04 03:38:36PM
Wow thanks wallybear!

I do not use Geektool, but I like your clever awk scripts just the same. Why use perl when awk will do :) I will have to create a little script from your post.

From the command-line I have a little shell script snippet I use in my scripts for text standout:


if tty -s <&1; then
        rev=`tput rev`
        sgr0=`tput sgr0`
else
        rev="_^H"
        sgr0=""
fi
This is a bourne shell snippet of course. What does this snippet do? The test redirects STDOUT to STDIN and tests to see if it is a terminal. This will do the right thing when the command is invoked in a pipeline depending on whether this was the last command or not.

In the case of a terminal do the tput commands. rev is the escape sequence for reverse video mode and sgr0 is for standard graphics mode. (the default for a terminal) The tput command uses curses to see what the right codes are for your current terminal.

Over the years I have learned a few tricks here. What you really want is:


        rev=`NCURSES_NO_PADDING=1 tput rev`
        sgr0=`NCURSES_NO_PADDING=1 tput sgr0`
I have seen some really horrible terminal DBs, and the environment variable does not hurt if you are using a historical curses either.

Also, I used to do a test of the exit status of the tput command, something like if tput os; then ... to see if overstrike was available. I learned the hard way that different systems do different things to the exit status for the tput command, so I just do not check and use reverse video mode instead.

Phew, now onto the other case, not a terminal. In that case I assume that you are doing a pipe, using a pager, or a hardcopy. I just do the underline for hardcopy device. The trick to getting a backspace into a file is to do this command from a shell:


cat >filename
Now type Ctrl+V Ctrl+H Return Ctrl+D Then just copy and paste the odd character where ever you need it in whatever editor you happen to use for the ^H BS character. Another thing that is useful is to use bold mode. On old daisy-wheel printers this was naturally character backspace character but the simple snippet I have above will not do here because you have to duplicate each character and that depends on what it actually is. Specifically, A is A^HA while B is B^HB.

Now in awk I do some thing like this whenever I need a standout character:


printf("%s%c%s", rev, c, sgr0)
Inline in a shell script just do the appropriate quoting and "$rev" and "$sgr0". To get this to work right in all cases you need to escape every character you wish to standout because the old hardcopy trick only affects one character. That is often the simplest thing to do and does not make a difference for simple shell scripts. Of course you can be fancy and check to see if the length of rev is non-zero and do other more complicated things like grouping all of the standout character in one rev/sgr0 pair in the case of a terminal if you care to.

I typically invoke these in an awk script like this:


/usr/bin/awk "$foo" rev="$rev" sgr0="$sgr0"
Now what if you do not want any standout characters, say you are outputting to a log file. That is simple enough, just put a col -bx at the end of your pipeline. That will strip-off the standout characters. That col command is very handy, it is a quick way to get nicely readable text files from a man command without all the embellishment in case you do not like the pretty printing in postscript output, and you do not have to care about whether it is a historical roff or GNU roff on the system you are using. Also, piping into the less command gives very good results, with whatever you wanted in standout mode appearing either as reverse video or underlined depending on your terminal configuration.

Finally I just noticed this about the posted hint that was the start of this long comment. My hunch is that the 'echo backticks' are extraneous in the original hint posted by wallybear :)

[ Reply to This | # ]

Even more fun with cal and GeekTool
Authored by: redclawx on Jun 30, '04 09:48:32PM
I have been able to combine several of the above comments together to get a three calendar layout. The layout is month below month, not month next to month but it's better than nothing. Also the alignment between the months isn't exact. The current month is indented by 1 character, while the previous and next month aren't. The original code was written by wallybear and dILVISH. Also the rewritten code works just fine with GeekTool, even on multiple lines (I've set up a Shell entry on my system.)

#!/bin/sh

month=`date +%m`
year=`date +%Y`

nextMonth=$(($month+1))
lastMonth=$(($month-1))

if [[ $nextMonth -gt 12 ]]
then
        nextMonth=1
        year=$(($year+1))
fi

if [[ $lastMonth -eq 0 ]]
then
        lastMonth=12
        year=$(($year-1))
fi

cal $lastMonth $year
cal | awk '{ if (substr($0,1,2) == " 1")  print "                    1 "; \
do { prevline=$0; if (getline == 0) exit; print " "\
substr(prevline,0) " "; } while (1) }' | \
awk -v cday=`date "+%d"` '{ a=$0; sub(" "fill int(cday)" ","["fill int(cday)"]",a); print  a };'
echo
cal $nextMonth $year


[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: siliconjones on Jul 07, '04 10:23:17AM

I know its dreadfully simple butů

date | cal

appears to work.

[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: wallybear on Jul 07, '04 11:09:52AM
where's the difference?

cal and date | cal give the same identical output...

so why date | cal ?


[ Reply to This | # ]
Here is on three columns, but...
Authored by: wallybear on Jul 07, '04 02:06:36PM
Here is a simple modification to get the three months on three columns using the handy pr command:

#!/bin/sh

month=`date +%m`
year=`date +%Y`

nextMonth=$(($month+1))
lastMonth=$(($month-1))

if [[ $nextMonth -gt 12 ]]
then
        nextMonth=1
        year=$(($year+1))
fi

if [[ $lastMonth -eq 0 ]]
then
        lastMonth=12
        year=$(($year-1))
fi

doCal()
{
cal $lastMonth $year
cal | awk '{ if (substr($0,1,2) == " 1")  print "                    1 "; \
do { prevline=$0; if (getline == 0) exit; print " "\
substr(prevline,0) " "; } while (1) }' | \
awk -v cday=`date "+%d"` '{ a=$0; sub(" "fill int(cday)" ","["fill int(cday)"]",a); print  a };'
echo
cal $nextMonth $year
}


doCal | pr -3 -t
This will get you the following result in Terminal:

     June 2004                July 2004             August 2004
 S  M Tu  W Th  F  S    S  M Tu  W Th  F  S    S  M Tu  W Th  F  S
       1  2  3  4  5                1  2  3    1  2  3  4  5  6  7
 6  7  8  9 10 11 12    4  5  6 [7] 8  9 10    8  9 10 11 12 13 14
13 14 15 16 17 18 19   11 12 13 14 15 16 17   15 16 17 18 19 20 21
20 21 22 23 24 25 26   18 19 20 21 22 23 24   22 23 24 25 26 27 28
27 28 29 30            25 26 27 28 29 30 31   29 30 31
but...
while on Terminal the display is correct, GeekTool shows erratic behaviour in some column (a GeekTool displaying bug, I presume; no tabs or other strange characters are contained here).
Any suggestion?

[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: wallybear on Jul 08, '04 08:05:14AM
I found the problem in the three column display and I also analyzed the code made by redclawx and found some bad problems.
  1. In reassembling my code he forgot to declare the variable fill
  2. The code for computation of previous and next month around year boundaries is wrong: for example, if current month is Dec 2004 you will get displayed Nov 2005 / Dec 2004 / Jan 2005; if current month is Jan 2005 you will get Dec 2004 / Jan 2005 / Feb 2004.
  3. Parts of my code were superfluous for a US calendar.
So I rewrote the code, added the side-by-side three column display and the possibility to choose the months to be displayed, and made it more modular. Here is the result of my efforts (and, hopefully, the end of this quest):

#!/bin/sh

month=`date +%m`
year=`date +%Y`
currDay=`date "+%d"`

getDate()
{
# syntax: getDate monthGap
themonth=$(($month+$1))
theyear=$year
 if [[ $themonth -gt 12 ]]
 then
    themonth=$(($themonth-12))
    theyear=$(($theyear+1))
 fi
 if [[ $themonth -lt 1 ]]
 then
    themonth=$((12-$themonth))
    theyear=$(($theyear-1))
 fi
 echo $themonth " " $theyear
}

MarkToday()
{
awk -v cday=$currDay '{ fill=(int(cday)>9?"":" "); a=$0; sub(" "fill int(cday)" ","["fill int(cday)"]",a); print  a }'
}

doCalUS()
{
cal $(getDate -1)
echo
cal $month $year | awk '{ print " " $0 " " }' | MarkToday
echo
cal $(getDate 1)
}

doCalUS | pr -3 -t -i100 | colrm 22 23
You can paste this code directly in GeekTool. The code above is for US-kind calendars, and this is the result:

     June 2004              July 2004             August 2004
 S  M Tu  W Th  F  S    S  M Tu  W Th  F  S    S  M Tu  W Th  F  S
       1  2  3  4  5                1  2  3    1  2  3  4  5  6  7
 6  7  8  9 10 11 12    4  5  6  7[ 8] 9 10    8  9 10 11 12 13 14
13 14 15 16 17 18 19   11 12 13 14 15 16 17   15 16 17 18 19 20 21
20 21 22 23 24 25 26   18 19 20 21 22 23 24   22 23 24 25 26 27 28
27 28 29 30            25 26 27 28 29 30 31   29 30 31
You can get a slightly narrower calendar replacing the last line with this one:
doCalUS | pr -3 -t -i100 | colrm 22 24 | colrm 44 44
If you want an italian calendar, replace the lines from doCalUs() (included) to the end of script with the following:

ItaHdr()
{
  echo $1/$2 | awk '{ split("Gennaio/Febbraio/Marzo/Aprile/Maggio/Giugno/Luglio/Agosto/Settembre/Ottobre/Novembre/Dicembre",arr,"/"); \
  split($0,arg,"/"); a=arr[int(arg[1])] " " arg[2]; print substr("          ",1,(21-length(a))/2) a; }'
  echo " Lu Ma Me Gi Ve Sa Do"
}

MoIsFirstDay()
{
awk '{nl=0; getline; getline; if (substr($0,1,2) == " 1")  {print "                    1 "; nl=1; } \
do { prevline=$0; if (getline == 0) { if (nl == 0) print ; exit;} print " " substr(prevline,4,17) " " substr($0,1,2) " "; } while (1); }'
}

doCalIta()
{
ItaHdr $(getDate -1); cal $(getDate -1) | MoIsFirstDay
ItaHdr $month $year ; cal $month $year  | MoIsFirstDay | MarkToday
ItaHdr $(getDate 1) ; cal $(getDate  1) | MoIsFirstDay
}

doCalIta | pr -3 -t -i100 | colrm 22 22 | colrm 46 46
And here is the result:

     Giugno 2004           Luglio 2004           Agosto 2004
 Lu Ma Me Gi Ve Sa Do  Lu Ma Me Gi Ve Sa Do  Lu Ma Me Gi Ve Sa Do
     1  2  3  4  5  6            1  2  3  4                     1
  7  8  9 10 11 12 13   5  6  7[ 8] 9 10 11   2  3  4  5  6  7  8
 14 15 16 17 18 19 20  12 13 14 15 16 17 18   9 10 11 12 13 14 15
 21 22 23 24 25 26 27  19 20 21 22 23 24 25  16 17 18 19 20 21 22
 28 29 30              26 27 28 29 30 31     23 24 25 26 27 28 29
                                             30 31
Also in this case, you ca get a narrower display replacing the last line with this one:
doCalIta  | pr -3 -t -i100 | colrm 22 23 | colrm 46 47
The shell commands used in this script are pr (for columnize output) and colrm (to remove some blank column in eccess).
As you can see the code is modular, so you can easily modify for other localizations.
The function getDate() gets called for displaying of months; it allows you to choose which months to consider: getDate 1 means one month after current, getDate -3 means the third month before the current, and so on. So, if you prefer (ennisdb? are you reading this?) to display the current month and the next two instead of the default setting, you simply have to change the doCalUs funtion to look like this one:

doCalUS()
{
cal $month $year | awk '{ print " " $0 " " }' | MarkToday
echo
cal $(getDate 1)
echo
cal $(getDate 2)
}
and here is the result:

     July 2004             August 2004           September 2004
 S  M Tu  W Th  F  S    S  M Tu  W Th  F  S    S  M Tu  W Th  F  S
             1  2  3    1  2  3  4  5  6  7             1  2  3  4
 4  5  6  7[ 8] 9 10    8  9 10 11 12 13 14    5  6  7  8  9 10 11
11 12 13 14 15 16 17   15 16 17 18 19 20 21   12 13 14 15 16 17 18
18 19 20 21 22 23 24   22 23 24 25 26 27 28   19 20 21 22 23 24 25
25 26 27 28 29 30 31   29 30 31               26 27 28 29 30
This should satisfy ennisdb. : )
(Note: getDate has a range of +/- 12 months max around the current date)

Happy GeekTooling !


[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: redclawx on Jul 08, '04 06:22:07PM

wallybear,
This is why I'm not a programer. :P fill is a variable? Missed that one, I thought it was a unix command. Once I get home I'll have to update my code in GeekTool. Thanks for the effort you (and everyone) has put into this.



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: wallybear on Jul 09, '04 05:32:25AM

Not a programmer? You did a good work anyway... Just a little too much cut and paste. :)
I'm not a programmer too (for CLI, at least, I work in Cocoa and 4D), but man pages and online Linux-oriented sites are really plenty of infos.
CLI programming is really fun.



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: Sigma on Jul 25, '04 08:16:35PM

This is really useful... I've been tinkering with it for a while and I can't seem to get what I want. I want all 12 months of the current year with the current date highlighted. And I wanted them to be horizontal. The clocest I have gotten is having the full year in the usual cal style... any suggestions?



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: icerabbit on Aug 02, '04 11:31:26AM

The only odd thing is, with a copy/paste into GeekTool, I get the month August three times. Not July - August - September



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: gent99 on Aug 03, '04 05:48:03AM

Strange things happen in August:

This little Script displays an error only in August:

#!/bin/sh
month=`date +%m`
themonth=$(($month+$1))
echo $themonth


Error: 08: value too great for base (error token is "08")

Every other month works fine.

Any U++x freak who can help us?



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: icerabbit on Aug 03, '04 08:39:36AM

I have the same error line.
Will see if there's a way to contact Wallybear.



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: Herbo on Aug 03, '04 01:06:16PM

The problem seems to be how bash handles leading zeros, it treats the number as octal rather than base 10. Hence 8 is an invalid octal number (valid range being 0 to 7).

Try removing the leading zero from the month by changing the month assignment line to:

month=`date +%m | sed -e 's/^0//'`

-Herbo



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: icerabbit on Aug 03, '04 06:25:42PM

By Joe,
That works!
Thanks Herbo :)



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: gent99 on Aug 04, '04 03:30:58AM

Actually this is a bug in bash. look here:

http://lists.debian.org/debian-boot/2000/05/msg00287.html

i managed to fix it with the following code:

month=`expr $month + 0`

this is working too.



[ Reply to This | # ]
August bug - A solution to that nasty bash bug
Authored by: wallybear on Sep 06, '04 05:52:28AM

The problem is due to a bug of bash. it treats '08' as an octal, because of the leading zero.
The only available token of the date command to get the month's number gives a number with a leading zero for the range 1..9 (01..09).
A simple solution (btw I hope that a simpler one exists) is to replace the following line at the beginning of the script:

month=`date +%m`

with this one:

month=`date +%m | awk '{print int($0)}'`

this will strip the leading zero if present and fix the bug.
The bug does not show with the day's number as in this case the leading zero is stripped by the appropriate 'date' token.

Happy geektooling...



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: theupperhand on Mar 24, '09 06:47:48PM

i really like this, though i would like to have the full year. i've been tinkering and know how to make previous and future months display, but can't figure out to make it display properly except in 1 column. and having the previous and future months doesn't give me the whole year either. any help is appreciated.



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: theupperhand on Apr 02, '09 08:40:19AM

i think i figured it out. i tried:

cal -y | awk -v cday=`date "+%d"` '{ fill=(int(cday)>9?"":" "); \
a=$0; sub(" "fill int(cday)" ","["fill int(cday)"]",a); print a }'\

and it appears to work, it shows the full year with the current day between square brackets.



[ Reply to This | # ]
The ultimate 3-column calendar
Authored by: theupperhand on Apr 02, '09 08:50:05AM

nevermind, this still doesn't work right. i noticed that other days are highlighted too, but only in 4 other months.



[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: zisht on Oct 28, '05 05:44:12PM

Sorry, but I just got into GeekTool and ran across this post as old as it maybe. Here is my simple solution placed in a zsh script:


#! /bin/zsh
local A="`print | tr '\012' '\001'`"
local today=`date | awk '{print $3}'`
date "+  %a %b %d, %Y%n        %H:%M"
cal | tail -n -7 | sed "s$A $today$A($today)$A" | \
sed "s$A$today $A($today)$A" | \
sed "s$A $today $A($today)$A"

Maybe over simplified, but I've tried my best without including the localization.

Here is the output:


  Sat Oct 29, 2005
        09:36
 S  M Tu  W Th  F  S
                   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


[ Reply to This | # ]
Faster and more flexible with perl
Authored by: bharris on Aug 19, '08 04:56:49AM
The 3 column version looks great, but seems to have to run a lot of stuff. Try this one, all perl -- runs about twice as fast:
#! /usr/bin/perl -w
# multi-column calendar

# setup
$nm		= 3;	# number of months to output
$ns		= 2;	# number of spaces between months

################################################################################

#initialize
$fw		= $ns + 20;		# month field width
@c		= ();			# $c[month index][line]

(undef,undef,undef,$mday,$mon,$year) = localtime;
$mday+=0;
$mon++;
$year+=1900;


$tm = $mon;		# this month
$ty = $year;	# and year

# count back
$i = int(($nm - 1) / 2);
while ($i--) {
	if (--$tm==0) { $tm = 12; $ty--; }
}

# get calendars
foreach $i (1..$nm) {

	$_ = `cal $tm $ty`;
	s/^|$/ /gm;
	if ($tm == $mon) { s/ ( ?$mday) /[$1]/ }
	
	push @c, [ split /n/ ];
	
	if (++$tm==13) { $tm = 1; $ty++; }

}
	
# print calendars
foreach $l (0..7) {

	foreach (0..$nm-1) {
		printf "%-${fw}s", $c[$_][$l] || "";
	}
	
	print "n";
}


exit(0);


[ Reply to This | # ]
Even more fun with cal and GeekTool
Authored by: auco on Jun 12, '10 11:39:48AM
I found that GNU gcal is compatible to OSX (I know it compiles and installs on 10.5 and 10.6)

1. Go to http://www.gnu.org/prep/ftp.html and connect to a ftp server
2. Download gcal
3. Install with Terminal:
cd ...and drag downloaded folder into terminal window
./configure
sudo make install
4. call
gcal -s1 -i 2011


                                  2011

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

see here for a quick tutorial: http://www.mostlymaths.net/2010/04/gcal-ultra-powerful-command-line-gnu.html
Edited on Jun 12, '10 11:40:30AM by auco


[ Reply to This | # ]