A simple reminder script for beginners to shell scripting.

(Apologies for any typos.)

Well hands up those who have been in the following situation(s):-
Your partner, (in my case the missus), sees that you are messing
with your machine and says something like, "can you keep an eye
on the dinner, I am going out shopping", and you look up glazed
eyed and say, "yes dear".
Sadly you forget and the dinner is burnt...
WW III is about to start... ;oD

Own up now, c'mon hands up!
Ah yes, nearly everyone. Those with their hands down cannot be
trusted... ;oD

The wife did just that to me and that gave me an idea, the
script below...

It is a piece of code that beginners could understand as a
practical and useful starting point to learn simple shell scripting.
It is called 'reminder' and generates a seriously annoying pop-up
every 30 to 300 seconds, programmable, with a reminder text of
your choice.
As a learning tool this script contains a lot of simple shell
stuff.
Arguments, variables, conditions, for loop, while loop, launching
another script, creating the script to launch, ANSI escape codes
to name but a few...

Written on OSX 10.7.5 default shell, tested on CygWin.
I am assuming it works on Linux flavours so just change the
script yourselves and notify this thread of your modifications;
IF there are any...

If you want this to work on CygWin then read the 'while true'
section and edit as required.

This is just superb for remembering your anniversary, the wife's
birthday, etc, etc, as it is SOOOO annoying...

This version is Public Domain and will not be uploaded anywhere
else.

The much simpler original is on 'code.activestate.com' also PD.

Enjoy finding simple solutions to often very difficult problems...

LBNL, for beginners, try and add a 1 second beeping sound for the
various *NIX flavours...

#!/bin/sh
# reminder
# Usage: /full/path/to/reminder "Your text here with spaces inside double quotes." Secs<CR>...
# Written on OSX 10.7.5 default shell, also tested on a CygWin bash shell...
# This version issued as Public Domain to http://www.unix.com/ ...

# On program entry place the first program argument "$1" into a variable called "text".
text=$1
# Now place "$2" into a variable called "countdown".
countdown=$2

# Clear the terminal window using terminal ANSI escape sequences...
printf "\033[2J\033[H"

# Now take "$1" OR "$2" and compare them as a _string_ literal to a NULL _string_, then if true......
if [ "$1" == "" ] || [ "$2" == "" ]
then
	# ......ensure that the default timer countdown value at least exists......
	countdown=30
	# ......ensure that a valid _string_ literal exists and......
	text="You have started reminder, what have you forgotten?"
	# ......print a usage message to the terminal window.
	echo ""
	printf "\033[1;31m"'Usage: /full/path/to/reminder "Your text here inside double quotes." Secs<CR>'"\033[0m\n"
fi

# Ensure a valid working numerical value for the timer countdown...
str_len=`printf "${#countdown}"`
str_len=$[ ( $str_len - 1 ) ]
for n in $( seq 0 1 $str_len )
do
	number=`printf "${countdown:$n:1}"`
	number=`printf "%d" \'$number`
	# If any characters other than contiguous numbers exist then set the default countdown value.
	if [ $number -le 47 ] || [ $number -ge 58 ]
	then
		countdown=30
		break
	fi
done

# Now ensure it is within given the limits, 30 to 300...
if [ $countdown -le 29 ] || [ $countdown -ge 301 ]
then
	countdown=30
fi

# Print the __arguments__ in parent window...
echo ""
echo "$text..."
echo "Timer=$countdown seconds..."
echo ""
echo "Press Ctrl-C in this window to stop..."
echo ""

# Now create a zero length file, (in this case), into /tmp/reminder.sh.
> /tmp/reminder.sh
# Ensure that once created it is able to be executed.
chmod 755 /tmp/reminder.sh

# Now create the relevant file to run externally.
# A shebang line is the first one to be APPENDED to the zero length file.
echo "#!/bin/sh" >> /tmp/reminder.sh
# Using "printf" to print the "text" and ANSI escape, "\", codes to set the "text" to bold, 12 lines
# down and 3 spaces in. Reset the "text" back to normal and then APPEND again to /tmp/reminder.sh.
# The "\n" are just newlines to remove the cursor away from your string when printed.
echo "printf '\033[1m\033[12;3f$text\033[0m\n\n\n'" >> /tmp/reminder.sh
# Add a delay to this code and APPEND again to /tmp/reminder.sh.
echo "sleep 3" >> /tmp/reminder.sh
# Ensure that after the delay this new script exits with a return code of 0 and APPEND to /tmp/reminder.sh.
echo "exit 0" >> /tmp/reminder.sh
# The new script is now ready to be called.

# Now loop this new script indefinitely until "Ctrl-C" is pressed in the parent terminal window to stop.
while true
do
	# Display your reminder for about 3 seconds...
	# The "&" means that the new script _divorces_ itself from the parent...
	# Comment out the line below when used with CygWin...
	xterm -e /tmp/reminder.sh &
	# Uncomment out the line below when used with CygWin..."
	# mintty /tmp/reminder.sh &
	# Use Ctrl-C to stop during this "countdown" break after xterm has closed down...
	sleep $countdown
done
# Program end...

Hi Wisecracker, nice idea for a script..

Here are a couple of remarks, so it could be improved further:

  1. The shebang is #!/bin/sh , so the script should conform to Posix Shell Standards and not use bash code..

2.:

if [ "$1" == "" ] || [ "$2" == "" ]

should be

if [ "$1" = "" ] || [ "$2" = "" ]
str_len=`printf "${#countdown}"`

Can be written as:

str_len=${#countdown}
str_len=$[ ( $str_len - 1 ) ]

$[ ... ] is deprecated bash code. It should be:

str_len=$(( str_len - 1 ))
for n in $( seq 0 1 $str_len )

should be:

n=0
while [ $n -le $str_len ]; 
do
  ...
  n=$((n+1))
done
number=`printf "${countdown:$n:1}"` 

could be written as number=${countdown:$n:1} , but would still be bash code.
Consider using ${var%"${var#?}"} for example and vary the number of question marks...
Another option would be to replace the for loop with a case statement

case $countdown in 
  (*[!0-9]*) countdown=30
esac
echo "printf '\033[1m\033[12;3f$text\033[0m\n\n\n'"

For security and other reasons it is best to not use the format field for uncontrolled data. So perhaps something like:

echo "printf '\033[1m\033[12;3f%s\033[0m\n\n\n' \"$text\""
  1. There should be a wait statement after the last done
1 Like

Hi Scrutinizer...

Thanks a lot...

Consider most will be incorporated soon...

I will leave the existing one and post a replacement as the existing one
works in CygWin and bash does have some minor foibles on CygWin.

One thing though why do I need a wait when it will never
be reached even when Ctrl-C is pressed?

I thought that in theory every time the "xterm" window closed there
would be more than enough time for the system to catch up; I even
assumed there would be no memory leak(s)...

I had mine on all day on this machine without a hitch...

Hi Wisecracker. True, I guess. I habitually use a wait statement to wait for background processes. That way I do not have to think, when the while true loop is changed to something else in the future for example...