The CS department at ANU runs a cake club. The club has a manager whose responsibility is to notify every club member about every fortnightly meeting via email, and establish whose turn it is to bring the cake.
The member list is maintained in the file members.txt which
has the following CSV format: a number of lines, each in the format
email@address,full name[,status]
This is an example of such file:
u1234456@anu.edu.au,Alexei B Khorev rms@fsf.org,Richard M Stallman,HonMem u2345678@anu.edu.au,Ian Barnes torvalds@transmeta.com,Linus B. Torvalds,HonMem chris.johnson@anu.edu.au,Chris Johnson
Theer are two categories: honorary members (marked by HonMem in the
3rd field)
and regular members (with no 3rd field). Only regular members
have to provide a cake
for every meeting. The turns for cake duty are regulated by the
roster.txt file, which lists all
regular members in order of duty. The format of the roster.txt file is the
same as the 2 fields of the members.txt.
The initial roster.txt can be easily generated from the
members.txt file by running the command:
shell-prompt> grep -v HonMem members.txt >roster.txtwith the result (numbers then added for clarity with the
-n switch on cat).
shell-prompt> cat -n roster.txt
1 u1234456@anu.edu.au,Alexei B Khorev
2 u2345678@anu.edu.au,Ian Barnes
3 chris.johnson@anu.edu.au,Chris Johnson
The first member on the list is the person who has to bring cake for the next club meeting.
We rely on the simplifying constraint that none of the email addresses,
nor any part of the full name contain the pattern HonMem. We could
be smarter and not need to reply on this—an exercise for the
reader (awk can do a pattern match selection on
individual fields.)
The task is to write a bash script called cake to
Write the script in debugging mode: that is, output (echo) the list of email commands, rather than actually executing them.
The command cake will be run as follows:
shell-prompt> ./cake < members.txt
The output will look something like this:
Hello, Alexei! Remind you that the cake club is meeting today at 10.30 am. This time it is your turn to bring the cake! See you there. The Cake club manager (sending to u1234456@anu.edu.au) Hello, Ian! Remind you that the cake club is meeting today at 10.30 am. See you there. The Cake club manager (sending to u2345678@anu.edu.au) .... .... .... .... .... .... .... .... .... The new roster is 1 u2345678@anu.edu.au,Ian Barnes 2 chris.johnson@anu.edu.au,Chris Johnson 3 u1234456@anu.edu.au,Alexei B Khorev
Result
#!/bin/bash
#who is the caker man today
caker=$(head -1 roster.txt | cut -d',' -f2)
caker_email=$(head -1 roster.txt | cut -d',' -f1)
echo The roster man today is $caker
echo His email address is $caker_email
echo
#looping through members.txt list and sending emails
while read line
do
email=$(echo $line | cut -d',' -f1)
fn=$(echo $line | cut -d',' -f2 | cut -f1)
echo Hello, ${fn}!
echo Remind you that the cake club is meeting today at 10.30 am.
if [ $caker_email == $email ]
then
echo This time it\'s your turn to bring the cake!
fi
echo See you there.
echo The Cake club manager, `whoami`
#to simulate sending the email
echo "(sending to $email)"
echo
done
#update the roster
# use tail with the '+' option to only pick
#all lines but the last one in the file
tail +2 roster.txt > tmp.txt
head -1 roster.txt >> tmp.txt
mv tmp.txt roster.txt
echo The new roster is
cat -n roster.txt
Result
shell-prompt> cat addmember
#!/bin/bash
#check if there are CLA for adding new member
if [ $# -eq 2 ]
then
if grep $1 members.txt > /dev/null
then
echo "You are already a member"
exit 1
else
echo $1,$2,NewMem > members.txt
echo The new members list is
cat members.txt
fi
else
echo "Usage: addmember email@address full_name"
exit 1
fi
The cake script also gets modified:
#!/bin/bash
#who is the caker man today
caker=$(head -1 roster.txt | cut -d',' -f2)
caker_email=$(head -1 roster.txt | cut -d',' -f1)
echo The roster man today is $caker
echo His email address is $caker_email
echo
#looping through members.txt list and sending emails
while read line
do
email=$(echo $line | cut -d',' -f1)
fn=$(echo $line | cut -d',' -f2 | cut -f1)
echo Hello, ${fn}!
echo Remind you that the cake club is meeting today at 10.30 am.
if [ $caker_email == $email ]
then
echo This time it\'s your turn to bring the cake!
fi
echo See you there.
echo The Cake club manager, `whoami`
#to simulate sending the email
echo "(sending to $email)"
echo
done
#update the roster
grep NewMem members.txt | cut -d',' -f1,2 >> roster.txt
#using the necessary option to only pick all lines but the last one in the file
tail +2 roster.txt > tmp.txt
head -1 roster.txt >> tmp.txt
mv tmp.txt roster.txt
echo The new roster is
cat -n roster.txt
This can be a bit hard.
Modify the cake script to eliminate "sending emails"
if the script has already been run recently: check whether the
roster.txt file was modified during last 7 days (assume
that the roster.txt file can be only modified by the
cake script).
Result
#!/bin/bash
#checking if the script has been run recently
find . -mtime +8 | grep roster > /dev/null
if [ $? -eq 1 ]
then
echo The reminder has been already sent.
exit 1
fi
#who is the caker man today
caker=$(head -1 roster.txt | cut -d',' -f2)
caker_email=$(head -1 roster.txt | cut -d',' -f1)
echo The roster man today is $caker
echo His email address is $caker_email
echo
while read line
do
email=$(echo $line | cut -d',' -f1)
fn=$(echo $line | cut -d',' -f2 | cut -f1)
echo Hello, ${fn}!
echo Remind you that the cake club is meeting today at 10.30 am.
if [ $caker_email == $email ]
then
echo This time it\'s your turn to bring the cake!
fi
echo See you there.
echo The Cake club manager, `whoami`
# simulate sending the email
echo "(sending to $email)"
echo
done
#update the roster
grep NewMem members.txt | cut -d',' -f1,2 >> roster.txt
tail +2 roster.txt > tmp.txt
head -1 roster.txt >> tmp.txt
mv tmp.txt roster.txt
echo The new roster is
cat -n roster.txt
#Making new members into regular members
grep -v NewMem members.txt > tmp.txt
grep NewMem members.txt | cut -d',' -f1,2 >> tmp.txt
mv tmp.txt members.txt