Code shell
#!/bin/bash # given month, day and weekday, get the most recent year that match it usage() { echo "$(basename $0) weekday month day" echo "(example: $(basename $0) wed aug 3 )" exit 1 } # check for arguments if [ $# -ne 3 ]; then usage fi weekday=$1 month=$2 day=$3 # parse arguments, translate them to lowcase, truncate them to 3 chars weekday=$(echo $weekday | tr '[:upper:]' '[:lower:]' | cut -c1-3) month=$(echo $month | tr '[:upper:]' '[:lower:]' | cut -c1-3) # get the current date eval $(date "+thismonth=%m; thisday=%d; thisyear=%Y") # get month number and weekday number monthnum=$(echo $month | sed -e \ 's/jan/1/;s/feb/2/;s/mar/3/;s/apr/4/;s/may/5/;s/jun/6/;s/jul/7/;s/aug/8/;s/sep/9/;s/oct/10/;s/nov/11/;s/dec/12/') weekdaynum=$(echo $weekday | sed -e \ 's/mon/1/;s/tue/2/;s/wed/3/;s/thu/4/;s/fri/5/;s/sat/6/;s/sun/7/;') monthname=$(echo $month | sed -e \ 's/10/oct/;s/11/nov/;s/12/dec/;s/1/jan/;s/2/feb/;s/3/mar/;s/4/apr/;s/5/may/;s/6/jun/;s/7/jul/;s/8/aug/;s/9/sep/') # get the most recent year to start with if [ $monthnum -gt $thismonth ]; then mostrecent=$(($thisyear - 1)) elif [ $monthnum -eq $thismonth -a $day -gt $thisday ]; then mostrecent=$(($thisyear - 1)) else mostrecent=$thisyear fi echo $monthname $day $mostrecent # iterate over the years, looking for a match weekdaynum_of_that_year=$(date -d "$monthname $day $mostrecent" +%u) while [ $weekdaynum_of_that_year -ne $weekdaynum ]; do mostrecent=$(($mostrecent-1)) weekdaynum_of_that_year=$(date -d "$monthname $day $mostrecent" +%u) done # output result echo "Most recent year for weekday=$weekday, month=$month, day=$day is $mostrecent"
Code bash
(another way to implement it -- parse the output result of cal with sed, tr and cut) this
#!/bin/bash # given month, day and weekday, get the most recent year that match it # set -x usage() { echo "$(basename $0) weekday month day" echo "(example: $(basename $0) wed aug 3 )" exit 1 } # check for arguments if [ $# -ne 3 ]; then usage fi weekday=$1 month=$2 day=$3 # parse arguments, translate them to lowcase, truncate them to 3 chars weekday=$(echo $weekday | tr '[:upper:]' '[:lower:]' | cut -c1-3) month=$(echo $month | tr '[:upper:]' '[:lower:]' | cut -c1-3) # get the current date eval $(date "+thismonth=%m; thisday=%d; thisyear=%Y") # get month number and weekday number monthnum=$(echo $month | sed -e \ 's/jan/1/;s/feb/2/;s/mar/3/;s/apr/4/;s/may/5/;s/jun/6/;s/jul/7/;s/aug/8/;s/sep/9/;s/oct/10/;s/nov/11/;s/dec/12/') weekdaynum=$(echo $weekday | sed -e \ 's/mon/1/;s/tue/2/;s/wed/3/;s/thu/4/;s/fri/5/;s/sat/6/;s/sun/7/;') monthname=$(echo $month | sed -e \ 's/10/oct/;s/11/nov/;s/12/dec/;s/1/jan/;s/2/feb/;s/3/mar/;s/4/apr/;s/5/may/;s/6/jun/;s/7/jul/;s/8/aug/;s/9/sep/') # get the most recent year to start with if [ $monthnum -gt $thismonth ]; then mostrecent=$(($thisyear - 1)) elif [ $monthnum -eq $thismonth -a $day -gt $thisday ]; then mostrecent=$(($thisyear - 1)) else mostrecent=$thisyear fi # parse the output of cal and get the answer while true; do cmd="cal -h ${monthnum} ${mostrecent} | grep \"\b${day}\b\" | sed 's/[ ][ ][ ]\|[ ][ ]\|[ ]/|/g; s/^|//; s/|/\n/g' | cat -n | grep \"\b${day}\b$\" | tr -s [:space:] ' '| cut -d' ' -f2" weekdaynum_of_that_year=$(eval $cmd) weekdaynum_of_that_year=$(($weekdaynum_of_that_year - 1)) [ $weekdaynum_of_that_year -eq 0 ] && weekdaynum_of_that_year=7 if [ $weekdaynum_of_that_year -eq $weekdaynum ]; then break; fi let mostrecent=$mostrecent-1 # echo -n "Debug: press [enter] to continue ..." # read ign done # output result echo "Most recent year for weekday=$weekday, month=$month, day=$day is $mostrecent"
-h option for cal is necessary for dealing with 'today' correctly spa
Code code