/home/wpollock1/public_html/restricted/ShellScripting/todo
#!/bin/bash
# todo - a Script to manage a "to do" list.
# This version supports a menu driven interface if called with no
# command line arguments.
#
# The (current) todo list/databse file format is one task per line.
#
# TODO: add a timestamp field, add a priority field (and then
# display tasks in priority order). Keep completed tasks
# in the database file, with another timestamp showing when
# the task was completed. (And a field to show it is done.
#
# Initially written 4/2007 by Wayne Pollock, Tampa Florida USA
#---------------------------version--------------------------
# $Id: todo,v 1.2 2007/04/12 08:43:29 wpollock Exp $
#-------------------------change-log-------------------------
# $Log: todo,v $
# Revision 1.2 2007/04/12 08:43:29 wpollock
# Final version (unless bugs are found!)
# In this version command line options were added,
# help was split into full help and brief usage messages.
#
PATH=/bin:/usr/bin
FILE="$HOME/.todo"
PROGNAME="${0##*/}"
VERSION=$(echo $Revision: 1.2 $ \
|awk '{ $1 = "'"$PROGNAME"' version "; $NF = ""; print}')
# Define shell functions to use:
add()
{
if [ -n "$MENU" ]
then
printf "(Add) Enter new task to add (hit enter to cancel): "
read TASK
[ -z "$TASK" ] && return
else
TASK="$1"
fi
if [ -z "$TASK" ]
then
printf '*** You must specify a task to add. ***\n'
return 1
fi
if [ ! -e "$FILE" ]
then > "$FILE"
chmod 600 "$FILE"
fi
echo "$TASK" >> $FILE
if [ -n "$MENU" ] # if interactive always display list
then
printf '\n\t List Updated:\n'
view
fi
}
view()
{
echo
if [ -r $FILE -a -s $FILE ]
then
nl -w3 -ba -s'. ' $FILE
else
printf '*** There is nothing to do. ****\n'
fi
echo
}
show_help()
{
cat <<-EndOfHelp
$PROGNAME manages a simple "to do" list of tasks.
If invoked with no command line arguments (other than -d)
a menu-driven interactive user interface is provided. From
this menu you can view the list, add to the (end of the) list,
remove an task (by its position) from the list, or display
this help message. Otherwise the action specified by
the option provided is done.
The to-do list is stored in a dot file in the user's home directory,
with the simple format of one task per line.
EndOfHelp
usage
}
usage()
{
cat <<-EndOfUsage
USAGE:
$PROGNAME [ -d ] [ -l ] [ -a TASK | -r NUM ]
$PROGNAME [ -d ] [ -h | -v ]
Options:
-d, --debug Turn on debugging mode.
-a, --add="TASK" Add the TASK string to the end of the list.
-r, --remove=NUM Remove the NUM-th task from the list.
-l,--list Display list of to-do tasks to standard output.
-h, --help Display this help message.
-v, --version Show author and version information.
If the -l option is combined with either -a or -r, the modified list
will be displayed.
EndOfUsage
}
remove()
{
if [ ! -r $FILE -o ! -s $FILE ]
then
printf '*** There are no tasks to remove. ****\n'
return 1
fi
if [ -z "$MENU" ]
then
ITEM="$1"
fi
while :
do
if [ -n "$MENU" ]
then
view
printf '(Remove) Enter task number to remove '
printf '(hit enter or "q" to cancel): '
read ITEM
[ -z "$ITEM" -o "$ITEM" = 'q' ] && return
fi
# Make sure $ITEM is a number, and between 1 and $NUM_TASKS:
if ! expr "$ITEM" : '[[:digit:]][[:digit:]]*$' >/dev/null
then printf "\t*** \"$ITEM\" is not a positive number! ***\n"
[ -n "$MENU" ] && continue || return 1
fi
NUM_TASKS=$(wc -l < $FILE)
if [ "$ITEM" -lt 1 -o "$ITEM" -gt "$NUM_TASKS" ]
then printf "\t*** You must enter a number between 1 and $NUM_TASKS! ***\n"
[ -n "$MENU" ] && continue || return 1
fi
TMP=$(mktemp)
trap 'rm $TMP' 1 2 3 15
if ! sed -e "${ITEM}d" "$FILE" >$TMP
then printf "\t*** Couldn't remove task \"$ITEM\" from list. ***\n" >&2
[ -n "$MENU" ] && continue || return 1
else cp $TMP "$FILE"
rm $TMP
if [ -n "$MENU" ] # if interactive always display list
then
printf '\n\t List Updated:\n'
view
fi
return
fi
done
}
menu()
{
# tput clear # erase the screen
MENU=1
PS3='Enter number from menu ('q' to quit, hit enter to redraw menu): '
select CMD in 'Add' 'Remove' 'View' 'Help'
do
case "$CMD" in
Add) add ;;
Remove) remove ;;
View) view ;;
Help) show_help ;;
*) case "$REPLY" in
q*|Q*) exit 0 ;;
*) usage ;;
esac ;;
esac
done
}
# Parse command line:
ARGS=$(getopt -n $PROGNAME -o dhla:r:v \
-l debug,help,list,add:,remove:,version -- "$@")
# if the getopt detected an error, display help and quit:
if [ $? -ne 0 ]
then
usage
exit 1;
fi
# Reset the positional parameters:
# Note the Gnu getopt used adds quotes to the values. To remove them
# we need to use eval as shown.
eval set -- "$ARGS"
MENU=
AOPT=
LOPT=
ROPT=
until [ "$1" = "--" ]
do
case "$1" in
-d|--debug) set -x ;;
-h|--help) show_help; exit 0 ;;
-l|--list) LOPT=1 ;;
-a|--add) AOPT=1; TASK="$2"; shift ;;
-r|--remove) ROPT=1; NUM="$2"; shift ;;
-v|--version) echo "$VERSION"; exit 0 ;;
esac
shift
done
shift # Remove the '--'.
if [ $# -ne 0 ]
then
usage
exit 1
fi
if [ -z "$AOPT" -a -z "$ROPT" -a -z "$LOPT" ]
then
menu
exit
fi
if [ -n "$AOPT" -a -n "$ROPT" ] # both not legal!
then
usage
exit 1
fi
if [ -n "$AOPT" ]
then
TASK="$(eval echo $TASK)" # remove the quotes added by getopt
add "$TASK"
elif [ -n "$ROPT" ]
then
NUM="$(eval echo $NUM)" # remove the quotes added by getopt
remove "$NUM"
fi
# -l option legal by itself, or with -a or -r:
if [ -n "$LOPT" ]
then
view
fi