Edit: This is version 2.0. One thing version 1.0 could not handle is running something every other week. This version handles that and it now requires my datecalc script. You may need to adjust the alias if you install datecalc somewhere other than /usr/local/bin.
To understand to even/odd stuff: datecalc -j can return a day number for a given month day and year. And datecalc -d can return a numeric day-of-week. Subtract the second from the first and you get the day number of the sunday that starts the week. Divide that by 7 and you get a week number. Now we just need to test that for even or odd.
And now the code...
#! /usr/bin/ksh
alias datecalc=/usr/local/bin/datecalc
# weekselector --- script to assist in scheduling cron jobs
# Perderabo Oct 11, 2003
#
# example:
# You want to run command1 on the first monday of each month and
# you want to run command2 on the last monday of each month.
# Just use this syntax:
#
# 0 0 * * 1 /usr/local/bin/weekselector 1st && command1
# 0 0 * * 1 /usr/local/bin/weekselector last && command2
#
# Version 2.0 March 23, 2005
#
# You can now use "even" or "odd" to run commands every other week.
# Whether or not a week is "even" or "odd" is arbitrary, but if one week
# is "odd", the next will be "even". An "even" Monday will be in the same
# week as an "even" Tuesday.
integer month day year first last leap
set -A mdy $(date "+%m %d %Y")
month=${mdy[0]}
day=${mdy[1]}
year=${mdy[2]}
#date "+%M %d %Y" | read month day year
case $1 in
even|Even|EVEN|odd|Odd|ODD)
integer dow mjd fmjd wk
dow=$(datecalc -d $year $month $day)
mjd=$(datecalc -j $year $month $day)
((fmjd=mjd-dow))
((wk=fmjd/7))
((wk=wk+${#1}))
((wk/2*2 == wk))
exit $?
;;
1|1st|1ST|first|First|FIRST) last=7 ;;
2|2nd|2ND|second|Second|SECOND) last=14 ;;
3|3rd|3RD|third|Third|THIRD) last=21 ;;
4|4th|4TH|fourth|Fourth|FOURTH) last=28 ;;
last|Last|LAST)
# ja fe ma ap ma jn jl ag se oc no de
set -A mlength xx 31 28 31 30 31 30 31 31 30 31 30 31
if ((month != 2)) ; then
last=${mlength[month]}
else
leap=0
if ((!(year%100))); then
((!(year%400))) && leap=1
else
((!(year%4))) && leap=1
fi
last=28
((leap)) && last=29
fi;;
*) exit 1;;
esac
((first=last-6))
((first<=day && day<=last))
exit $?