Customizing Your Calendar Program
Steven G. Isaacson
Our Human Resources department asked if it was possible
mail reminders about employee annual reviews. An additional
was that the reminders be mailed to more than one person:
leader, team leader, etc.
We considered writing a custom reminder program -- easy
to do with
cron and a shell script -- but when it came time to
upon a date format (would it be mm/dd/yy, mm/dd/yyyy,
1995?), we decided instead to use the existing calendar
which already knows how to handle dates in a variety
This article describes a shell script that works like
but adds the ability to send mail to more than one user,
lines per calendar entry, supports include files, and
for keywords like Daily, Monday, Tuesday, Weekend, etc.
The /usr/bin/calendar program is a handy reminder service.
By default it looks in your $HOME directory for a file
calendar and examines each line for a date. If the date
today or tomorrow (Monday is "tomorrow" for
Friday) then you
are sent reminder mail. On most systems, calendar is
Here are sample calendar entries:
March 10 -- Sys Admin budget meeting
Jan 5 1995 -- new workstations should arrive next week
Sep 10 -- Anniversary on Sep 20th Send flowers!
Note that line three contains two dates, the 10th and
the 20th. So mail is sent on September 9th and 10th,
and then again
on the 19th and 20th.
Although handy, the calendar program is limited. Only
line per entry is allowed and mail is sent to only one
of these problems were addressed with our custom calendar.sh
To support multiple email addresses, we had to do two
things: 1) decide
upon an extended format for the calendar entry (i.e.,
way to specify the email addresses), and 2) run calendar
The extended format is as follows:
[email address(es)]| [calendar entry]
petera sysadm@central| March 10 Sys Admin budget meeting
On March 9th and 10th this calendar entry will be sent
to petera and sysadm@central.
Running calendar Manually
/usr/bin/calendar is actually a shell script that uses
/usr/lib/calprog (a binary program) to figure out what
look for in the calendar file. Specifically, calprog
figures out which dates to look for by generating regular
-- one for today and one for tomorrow. On Fridays --
that Monday is "tomorrow" for Friday -- four
are generated. One for Friday, Saturday, Sunday, and
On September 7th, for example, calprog generated these
regular expressions. The first matches September 7 dates;
matches September 8 dates.
(^|[ (,;])([Ss]ep[^ ]* *|0*9/|\*/)0*7)([^0123456789]|$)
(^|[ (,;])([Ss]ep[^ ]* *|0*9/|\*/)0*8)([^0123456789]|$)
You'll probably never see a more complex regular expression
(for more information on regular expressions see Larry
Regular Expressions," Sys Admin September/October
vol. 1, no. 3). I was surprised to see that the second
and third letters
of the month are case-sensitive. Sep 7 is a valid calendar
but SEP 7 isn't!
The calendar program uses calprog to write the regular
expressions to a file. Then egrep, using the regular
written to the file, scans the calendar file in your
directory. To wit:
# create regular expression file
calprog > re.file
# egrep for matches
egrep -f re.file $HOME/calendar
The output, if any, is mailed to you. That's the stock
calendar program -- crude but effective.
Our version of calendar does the same thing, and more.
regular expressions for grabbing the correct dates are
the same way, with /usr/lib/calprog, but instead of
sending mail to whoever happens to be running the program,
sent to the name or names in the first field, the first
everything up to the first pipe symbol. If there is
no first field,
that is, no pipe symbol, then mail is sent to the current
Adding calendar.sh to a nightly cron job and specifing
the calendar file was now all that it took to send calendar
entries to more than one person. Our Human Resources
happy -- but only for a while. Almost immediately there
for multiple-line calendar entries.
Multiple-Line Calendar Entries
Making calendar.sh send more than one line of information
per entry was easy once the "trick" was figured
the problem. If all entries are only one line, there
isn't a problem.
But some entries are more than one line. So . . .
convert all multi-line
entries to one line, do what you normally do, then undo
conversion before sending the mail.
Here's an example of how it works. This three-line entry
sysadm| Sep 20 Big meeting Be \
is first converted to
sysadm| Sep 20 Big meeting <nl> Be <nl> There!
Each escape character at the end of the line is converted
to <nl> and then converted back again after the
processing is done. So, there are no multiple-line entries;
the problem is solved by ignoring it for a while.
Another way to support multiple-line calendar entries
is with include
files. For example: suppose you have quarterly employee
want to remind the mail recipients to, say, use a particular
way to remind them to use the form is by including the
form in the
mail. This feature was easy to add.
The include file syntax is:
[address]| [calendar entry [#f:[filename]]]
as, for example:
sysadm| Sep 20 Big meeting #f:/usr/uubob/big_notes
What happens is that after the calendar entry is selected,
the entry is scanned for the #f: keyword. If the keyword
found, the specified file is included in the email.
Included files are included via cat. That is, a shell
(cat [filename]) is executed from within the awk program
that searches for the #f: keyword. If cat is useful,
how about other commands? For example, df to show the
disk space, or who, to show who is still logged in early
the morning when cron runs calendar.sh.
The shell command syntax is:
[address]| [calendar entry [#!:[shell command]]]
sysadm| Sep 20 Big meeting #!:df bring disk space report
Suppose, now that you have a truly simple means of sending
or anyone else mail about current disk space, that you'd
like to have
the mail sent daily. You can't do it with the present
because once an entry is used, that's it -- no more
September 20 meetings until the next Sep 20, next year.
So, a nice
addition would be support for keywords such as "Daily,"
"Tuesday," etc. Adding new keywords to calendar.sh
is simple. For example, to support the days of the week,
to the regular expression list on Mondays, add "Tuesday"
the regular expression list on Tuesday, and so on. To
add "Daily" to the list each day. To support
add "Weekend" to the regular expression list
on Saturday and
Installing calendar.sh is easy. Create a calendar
file (or .calendar to avoid conflicts with /usr/bin/calendar)
in your HOME directory, then add an entry to your crontab
to run calendar.sh. Figure 1 shows a sample crontab
About the Author
Steven G. Isaacson has been programming professionally
since 1985. He works for
FourGen Software, the leading developers of accounting
CASE Tools for the UNIX market. He may be reached at
uunet!4gen!stevei or email@example.com.