记录日程安排脚本
这个脚本事实上是2个脚本,用来执行一个简单的日历程序。第一个脚本,addagenda.sh,它可以存储两种事件:可重复发生的、一次性发生的。它允许用户指定天数、周或是年。所有的日期都被合法化后保存了起来,同时在家目录下的.agenda文件中还有一行关于事件的描述信息。第二个脚本中,agenda.sh中核实所有的事件,会显示所有安排对应日期的日程。
我觉得这个脚本非常有用,特别是在记录生日和周年纪念的时候。它真的给我减少了很多麻烦。
代码:
addagenda.sh
01
#!/bin/sh
02
03
# addagenda.sh --提醒用户向事件脚本中添加新内容
04
05
agendafile="$HOME/.agenda"
06
07
isDayName()
08
{
09
# 返回值 0,成功;1,失败
10
11
case $(echo $1 | tr '[[:upper:]]' '[[:lower:]]') in
12
sun*|mon*|tue*|wed*|thu*|fri*|sat*) retval=0;;
13
*) retval=1;;
14
esac
15
return $retval
16
}
17
18
isMonthName()
19
{
20
case $(echo $1 | tr '[[:upper:]]' '[[:lower:]]') in
21
jan*|feb*|mar*|apr*|may*|jun*) return 0;;
22
jul*|aug*|sep*|oct*|nov*|dec*) return 0;;
23
*) return 1
24
esac
25
}
26
27
normalize()
28
{
29
# 返回的字符串中首字母大写,后续2个小写
30
echo -n $1 | cut -c1 | tr '[[:lower:]]' '[[:upper:]]'
31
echo $1 | cut -c2-3 | tr '[[:upper:]]' '[[:lower:]]'
32
}
33
34
if [ ! -w $HOME ]; then
35
echo "$0: cannot write in your home directory($HOME)" >&2
36
exit 1
37
fi
38
39
echo "Agenda: The Unix Reminder Service"
40
echo -n "Date of event(day mon, day month year, or dayname): "
41
read word1 word2 word3 junk
42
43
if isDayName $word1; then
44
if [ ! -z "$word2" ]; then
45
echo "Bad dayname format: just specify the day name by itself." >&2
46
exit 1
47
fi
48
date="$(normalize $word1)"
49
else
50
if [ -z "$word2" ]; then
51
echo "Bad dayname format: unknown day name specified" >&2
52
exit 1
53
fi
54
55
if [ ! -z "$(echo $word1 | sed 's/[[:digit:]]//g')" ]; then
56
echo "Bad date format: please specify day first, by day number" >&2
57
exit 1
58
fi
59
60
if [ "$word1" -lt 1 -o "$word1" -gt 31 ]; then
61
echo "Bad date format: day number can only be in range 1-31" >&2
62
exit 1
63
fi
64
65
if ! isMonthName $word2; then
66
echo "Bad date format: unknown month name specified." >&2
67
exit 1
68
fi
69
70
word2="$(normalize $word2)"
71
72
if [ -z "$word3" ]; then
73
date="$word1$word2"
74
else
75
if [ ! -z "$(echo $word3 | sed 's/[[:digit:]]//g')" ]; then
76
echo "Bad date format: year value should be 2000-2500" >&2
77
exit 1
78
elif [ $word3 -lt 2000 -o $word3 -gt 2500 ]; then
79
echo "Bad date format: year value should be 2000-2500" >&2
80
exit 1
81
fi
82
date="$word1$word2$word3"
83
fi
84
fi
85
86
echo -n "One-line description: "
87
read description
88
89
# Ready to write to data file
90
91
echo "$(echo $date | sed 's/ //g') | $description" >> $agendafile
92
93
exit 0
agenda.sh
01
#!/bin/sh
02
03
# agenda.sh --查看.agenda文件中是否有今明两天的安排
04
05
agendafile="$HOME/.agenda"
06
07
checkDate()
08
{
09
# Create the possible default values that'll match today
10
weekday=$1 day=$2 month=$3 year=$4
11
format1="$weekday" format2="$day$month" format3="$day$month$year"
12
# and step through the file comparing dates...
13
14
IFS="|" # the reads will naturally split at the IFS
15
16
echo "On the Agenda for today:"
17
18
while read data description; do
19
if [ "$date" = "$format1" -o "$date" = "$format2" -o "$date" = "$format3" ]; then
20
echo "$description"
21
fi
22
done < $agendafile
23
}
24
25
if [ ! -e $agendafile ]; then
26
echo "$0: You don't seem to have an .agenda file." >&2
27
echo "To remedy this, please use 'addagenda' to add events" >&2
28
exit 1
29
fi
30
31
# Now let's get today's date...
32
33
eval $(date "+weekday=/"%a/" month=/"%b/" day=/"%e/" year=/"%G/"")
34
35
day="$(echo $day | sed 's/ //g')" # remove possible leading space
36
37
checkDate $weekday $day $month $year
38
39
exit 0
addagenda.sh这个脚本,支持3中类型的事件:每周的(比如每个周三)、每年的(比如8月3号),以及一次性的(比如2010年1月10号)。而用户提供的日期会被程序压缩,比如用户给的日期是3 August,压缩后变为3Aug,或是Thursday变成了Thu。完成这个功能的代码是如下函数:
1
normalize()
2
{
3
# 返回的字符串中首字母大写,后续2个小写
4
echo -n $1 | cut -c1 | tr '[[:lower:]]' '[[:upper:]]'
5
echo $1 | cut -c2-3 | tr '[[:upper:]]' '[[:lower:]]'
6
}
agenda.sh脚本通过日期来核实事件。并且该脚本会将这个日期转换为3中可能的日期格式(dayname, day+month, day+month+year)。它仅仅是简单的和.agenda文件中的行比较下。如果有匹配,就显示给用户。
在我看来,最牛逼最狂霸酷炫拽的地方是如何应用一个eval表达式一次性的分配4个日期值给变量的:
1
eval $(date "+weekday=/"%a/" month=/"%b/" day=/"%e/" year=/"%G/"")
同样,一个接一个提取值也是可以的(比如,weekday="$(date +%a)"),但在有些非常罕见的情况中,这种方法可能会失效:在4个日期请求的中间部分,此时真实日期滚动到了新的一天,因此一个简洁的单一调用更好(注:这个单一的句子就相当于一个原子调用。类似操作系统中的竟态条件)。
运行脚本,测试一下:
01
$ addagenda
02
Agenda: The Unix Reminder Service
03
04
Date of event (day mon, day month year, or dayname): 31 October
05
One line description: Halloween
06
$ addagenda
07
Agenda: The Unix Reminder Service
08
09
Date of event (day mon, day month year, or dayname): 30 March
10
One line description: Penultimate day of March
11
$ addagenda
12
Agenda: The Unix Reminder Service
13
14
Date of event (day mon, day month year, or dayname): Sunday
15
One line description: sleep late (hopefully)
16
$ addagenda
17
Agenda: The Unix Reminder Service
18
19
Date of event (day mon, day month year, or dayname): marc 30 03
20
Bad date format: please specify day first, by day number
21
22
$ addagenda
23
Agenda: The Unix Reminder Service
24
25
Date of event (day mon, day month year, or dayname): 30 march 2003
26
One line description: IM Marv to see about dinner
27
28
Now the agenda script offers a quick and handy reminder of what's happening today:
29
30
$ agenda
31
On the Agenda for today:
32
Penultimate day of March
33
sleep late (hopefully)
34
IM Marv to see about dinner
35
36
Notice that it matched entries formatted as day+month, day of week, and day+month+year. For completeness, here's
37
the associated .agenda file, with a few additional entries:
38
39
$ cat ~/.agenda
40
14Feb|Valentine's Day
41
25Dec|Christmas
42
3Aug|Dave's Birthday
43
4Jul|Independence Day (USA)
44
31Oct|Halloween
45
30Mar|Penultimate day of March
46
Sun|sleep late (hopefully)
47
30Mar2003|IM Marv to see about dinner
这两个脚本在记录日记方面仅仅是起到了一个抛砖引玉的作用。要想搞的更好点,可以在脚本中做一点关于日期的数学运算。另外,如果匹配的日期没有日程安排,可以更人性化的输出一句别的什么内容。