第三章:Creating Utilities--30.記錄日程安排

   這個腳本事實上是2個腳本,用來執行一個簡單的日曆程序。第一個腳本,addagenda.sh,它能夠存儲兩種事件:可重複發生的、一次性發生的。它容許用戶指定天數、周或是年。全部的日期都被合法化後保存了起來,同時在家目錄下的.agenda文件中還有一行關於事件的描述信息。第二個腳本中,agenda.sh中核實全部的事件,會顯示全部安排對應日期的日程。
我以爲這個腳本很是有用,特別是在記錄生日和週年記念的時候。它真的給我減小了不少麻煩。

代碼: git

addagenda.sh shell

#!/bin/sh

# addagenda.sh --提醒用戶向事件腳本中添加新內容

agendafile="$HOME/.agenda"

isDayName()
{
	# 返回值 0,成功;1,失敗

	case $(echo $1 | tr '[[:upper:]]' '[[:lower:]]') in
		sun*|mon*|tue*|wed*|thu*|fri*|sat*) retval=0;;
		*) retval=1;;
	esac
	return $retval
}

isMonthName()
{
	case $(echo $1 | tr '[[:upper:]]' '[[:lower:]]') in
		jan*|feb*|mar*|apr*|may*|jun*) return 0;;
		jul*|aug*|sep*|oct*|nov*|dec*) return 0;;
		*) return 1
	esac
}

normalize()
{
	# 返回的字符串中首字母大寫,後續2個小寫
	echo -n $1 | cut -c1 | tr '[[:lower:]]' '[[:upper:]]'
	echo $1 | cut -c2-3 | tr '[[:upper:]]' '[[:lower:]]'
}

if [ ! -w $HOME ]; then
	echo "$0: cannot write in your home directory($HOME)" >&2
	exit 1
fi

echo "Agenda: The Unix Reminder Service"
echo -n "Date of event(day mon, day month year, or dayname): "
read word1 word2 word3 junk

if isDayName $word1; then
	if [ ! -z "$word2" ]; then
		echo "Bad dayname format: just specify the day name by itself." >&2
		exit 1
	fi
	date="$(normalize $word1)"
else
	if [ -z "$word2" ]; then
		echo "Bad dayname format: unknown day name specified" >&2
		exit 1
	fi

	if [ ! -z "$(echo $word1 | sed 's/[[:digit:]]//g')" ]; then
		echo "Bad date format: please specify day first, by day number" >&2
		exit 1
	fi

	if [ "$word1" -lt 1 -o "$word1" -gt 31 ]; then
		echo "Bad date format: day number can only be in range 1-31" >&2
		exit 1
	fi

	if ! isMonthName $word2; then
		echo "Bad date format: unknown month name specified." >&2
		exit 1
	fi

	word2="$(normalize $word2)"

	if [ -z "$word3" ]; then
		date="$word1$word2"
	else
		if [ ! -z "$(echo $word3 | sed 's/[[:digit:]]//g')" ]; then
			echo "Bad date format: year value should be 2000-2500" >&2
			exit 1
		elif [ $word3 -lt 2000 -o $word3 -gt 2500 ]; then
			echo "Bad date format: year value should be 2000-2500" >&2
			exit 1
		fi
		date="$word1$word2$word3"
	fi
fi

echo -n "One-line description: "
read description

# Ready to write to data file

echo "$(echo $date | sed 's/ //g') | $description" >> $agendafile

exit 0
agenda.sh
#!/bin/sh

# agenda.sh --查看.agenda文件中是否有今明兩天的安排

agendafile="$HOME/.agenda"

checkDate()
{
	# Create the possible default values that'll match today
	weekday=$1 day=$2 month=$3 year=$4
	format1="$weekday" format2="$day$month" format3="$day$month$year"
	# and step through the file comparing dates...

	IFS="|"    # the reads will naturally split at the IFS

	echo "On the Agenda for today:"

	while read data description; do
		if [ "$date" = "$format1" -o "$date" = "$format2" -o "$date" = "$format3" ]; then
			echo "$description"
		fi
	done < $agendafile
}

if [ ! -e $agendafile ]; then
	echo "$0: You don't seem to have an .agenda file." >&2
	echo "To remedy this, please use 'addagenda' to add events" >&2
	exit 1
fi

# Now let's get today's date...

eval $(date "+weekday=\"%a\" month=\"%b\" day=\"%e\" year=\"%G\"")

day="$(echo $day | sed 's/ //g')"    # remove possible leading space

checkDate $weekday $day $month $year

exit 0
addagenda.sh這個腳本,支持3中類型的事件:每週的(好比每一個週三)、每一年的(好比8月3號),以及一次性的(好比2010年1月10號)。而用戶提供的日期會被程序壓縮,好比用戶給的日期是3 August,壓縮後變爲3Aug,或是Thursday變成了Thu。完成這個功能的代碼是以下函數:
normalize()
{
	# 返回的字符串中首字母大寫,後續2個小寫
	echo -n $1 | cut -c1 | tr '[[:lower:]]' '[[:upper:]]'
	echo $1 | cut -c2-3 | tr '[[:upper:]]' '[[:lower:]]'
}
agenda.sh腳本經過日期來覈實事件。而且該腳本會將這個日期轉換爲3中可能的日期格式(dayname, day+month, day+month+year)。它僅僅是簡單的和.agenda文件中的行比較下。若是有匹配,就顯示給用戶。
在我看來,最牛逼最狂霸酷炫拽的地方是如何應用一個eval表達式一次性的分配4個日期值給變量的:
eval $(date "+weekday=\"%a\" month=\"%b\" day=\"%e\" year=\"%G\"")
一樣,一個接一個提取值也是能夠的(好比,weekday="$(date +%a)"),但在有些很是罕見的狀況中,這種方法可能會失效:在4個日期請求的中間部分,此時真實日期滾動到了新的一天,所以一個簡潔的單一調用更好(注:這個單一的句子就至關於一個原子調用。相似操做系統中的竟態條件)。


運行腳本,測試一下:
$ addagenda 
Agenda: The Unix Reminder Service 

Date of event (day mon, day month year, or dayname): 31 October 
One line description: Halloween 
$ addagenda 
Agenda: The Unix Reminder Service 

Date of event (day mon, day month year, or dayname): 30 March 
One line description: Penultimate day of March 
$ addagenda 
Agenda: The Unix Reminder Service 

Date of event (day mon, day month year, or dayname): Sunday 
One line description: sleep late (hopefully) 
$ addagenda 
Agenda: The Unix Reminder Service 

Date of event (day mon, day month year, or dayname): marc 30 03 
Bad date format: please specify day first, by day number 

$ addagenda 
Agenda: The Unix Reminder Service 

Date of event (day mon, day month year, or dayname): 30 march 2003 
One line description: IM Marv to see about dinner 

Now the agenda script offers a quick and handy reminder of what's happening today: 

$ agenda 
On the Agenda for today: 
Penultimate day of March 
sleep late (hopefully) 
IM Marv to see about dinner 

Notice that it matched entries formatted as day+month, day of week, and day+month+year. For completeness, here's  
the associated .agenda file, with a few additional entries: 

$ cat ~/.agenda 
14Feb|Valentine's Day 
25Dec|Christmas 
3Aug|Dave's Birthday 
4Jul|Independence Day (USA) 
31Oct|Halloween 
30Mar|Penultimate day of March 
Sun|sleep late (hopefully) 
30Mar2003|IM Marv to see about dinner
  這兩個腳本在記錄日記方面僅僅是起到了一個拋磚引玉的做用。要想搞的更好點,能夠在腳本中作一點關於日期的數學運算。另外,若是匹配的日期沒有日程安排,能夠更人性化的輸出一句別的什麼內容。
相關文章
相關標籤/搜索