Suppose I record my friends' birthdays in the file .birthdays in my home directory:
Charles Manson:11/12 Zsa Zsa Gabor:06/02 William H. Gates III:28/10
This reminder script will tell me whose birthday it is today.
#!/bin/bash
today=$(date +%d/%m)
lines=$(grep -n ${today} ~/.birthdays | cut -d: -f1)
for x in ${lines}
do
echo -n Today is
echo -n $(cut -d: -f1 ~/.birthdays | head -${x} | tail -1)
echo \'s birthday!
done
How does this work?
The first line runs the date command, and saves its output in the variable today. The argument to the date command tells it to print the date as a two-digit day-of-the-month number, followed by a slash, followed by a two-digit month-in-the-year number. This is the format I used for the birthday dates in the .birthdays file. (And as usual you're likely to run into trouble with American-style birthdays.)
The next line produces the line numbers within the file of all the people whose birthdays match today's date. (There might be more than one. This would be a little easier if we didn't have to allow for that possibility.) The grep command selects all lines from .birthdays which contain the string we just stored in ${today} and precedes each by its line number and a colon. The cut command divides its input up into fields using the delimiter character specified. Here that is the colon character; that's what the -d: option means. The -f1 option tells the cut command to only output the first of the fields it has divided each line into. So the output of the whole thing in $(...) is a list of the line numbers of the people whose birthday is today.
The loop performs one iteration for each number in the list ${lines}. For each of these it first prints 'Today is ' and doesn't move to the next line. (That's what the -n option for echo does.)
In the next line, the cut command takes the file ~/.birthdays and throws away everything after and including the first colon on each line. So it just keeps the names, and throws away the dates. The result of this is passed to the head command, which copies the first few lines of a file to its output and throws away the rest. How many? Well if there's no option, it's 10, but if you put a number there (with a minus sign before) then it takes exactly that many lines. So head -${x} after variable substitution is going to take all the lines up to and including the current value of $x. Finally the tail command throws away all but a few lines at the end of its input. With the option tail -1 it produces only the last line, which is the one we want, with the name of one of the people whose birthday is today.
The last line isn't very interesting. The only thing to watch out for is that the apostrophe had to be escaped, because otherwise bash would think it was the beginning of a string.
The next thing is to put a line into your .login file to run this script every time you log in. Any ideas?