ToDo list utility - suggestions/optimizations/refinements wanted



Hi everybody,

For the past couple of days, I've been working on this todo list script and I'm really happy with the way it works, but wanted to post it here before I go any futher, in case anybody had suggestions for optimizations or style errors. I'm a self-taught programmer, and I'm always interested in the "correct" way to do things, so please don't be shy about pointing out problems with the script, even if they're as simple as improper or hard to understand variable names (for example, following _The Practice of Programming_ by Kernighan & Pike, I've used single-letter local variables, but I'm worried that may obsfucate the code).

The script is a bare bones GTD-style (http://en.wikipedia.org/wiki/Getting_Things_Done) todo utility. Its datafile contains two tab-seperated fields: description and context. (In GTD, todo lists are organizaed by context - i.e. @work, @home, @computer, etc. - rather than priority or date.) The utility can read from and modify the datafile in various, powerful ways.

Usage: td <option>
-a add entry to datafile
-c list contexts
-d <regex> delete regex from datafile
-e <sed command> edit datafile using sed command
-h print this screen
-l <context> list items in specified context
-s <regex> search datafile for regex pattern

Thanks in advance for whatever guidence or help you can provide, and thanks for taking the time to evaluate my new pet script!

Best,
Mike

P.S. I believe this script to be extremely portable, but it does depend on sed, an awk that understands the -v switch, and a version of mktemp that takes the -t switch. BSD users should have no problems, but I'm not so sure about others (Linux, Cygwin, etc.).


-------<snip>------
#!/bin/sh
# $Id: td,v 2.2.1.2 2009/06/06 14:39:43 mike Exp $
#
# ToDo - a basic todo list utility

TODOFILE="$HOME/.todo/todo.txt"

# Copyright (c) 2009 Mike Rhodes <rhodes553@xxxxxxxxx>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

add () {
# Create tempfile
tempfile=$(mktemp -t todo)
if [ $? -ne 0 ]
then
echo >&2 "Error creating tempfile."
exit 1
fi

# Write user input to tempfile
echo "Enter todo items (CNTL-D to quit):"
echo "DESCRIPTION <tab> CONTEXT"
cat >> "$tempfile"

# Test for null input
if [ -s "$tempfile" ]
then
cat "$tempfile" >> "$TODOFILE"
echo "File written successfully."
else
echo "Nothing to write."
fi
rm "$tempfile"
exit 0
}

contexts () {
s="$(awk -F "\t" '{ print $2 }' $TODOFILE | sort -u)"
if [ -n "$s" ]
then
echo
echo "$s"
echo
else
echo "Empty file: $TODOFILE"
fi
exit 0
}

delete () {
# Create first tempfile
tempfile="$(mktemp -t todo)"
if [ $? -ne 0 ]
then
echo >&2 "Error creating tempfle."
exit 1
fi

# Print matches with sed
sed -n "/$1/p" "$TODOFILE" > "$tempfile"

# Check for zero file length
if [ -s "$tempfile" ]
then
echo
cat "$tempfile"
printf "Is this what you want to delete (y/n)? "

# Get response from user
read answer

# Exit unless they consent
if [ "$answer" != y ]
then
echo "File unchanged."
rm "$tempfile"
exit 0
fi

# Delete confirmed regex and overwrite tempfile
sed "/$1/d" "$TODOFILE" > "$tempfile"

# Clobber original file
cp "$tempfile" "$TODOFILE"
if [ $? -ne 0 ]
then
echo >&2 "Error copying file: $tempfile"
exit 1
else
echo "File successfully modified."
rm "$tempfile"
fi
else
echo >&2 "No match found."
rm "$tempfile"
exit 1
fi
exit 0
}

edit () {
echo
sed "$1" "$TODOFILE" | diff "$TODOFILE" -
printf "Are you sure this is the edit you want to make? (y/n) "
read answer
if [ "$answer" != y ]
then
echo "No edit performed."
exit 0
fi

tempfile="$(mktemp -t todo)"
if [ $? -ne 0 ]
then
echo >&2 "Error creating tempfile."
exit 1
fi

# Make the edit
sed -e "$1" "$TODOFILE" > "$tempfile"
cp "$tempfile" "$TODOFILE"
if [ $? -ne 0 ]
then
echo >&2 "Error copying file: $tempfile"
exit 1
else
echo "File successfully modified."
rm "$tempfile"
fi
exit 0
}

help () {
echo "Usage: ${0##*/} <option>"
echo " -a add entry to datafile"
echo " -c list contexts"
echo " -d <regex> delete regex from datafile"
echo " -e <sed command> edit datafile using sed command"
echo " -h print this screen"
echo " -l <context> list items in specified context"
echo " -s <regex> search datafile for regex pattern"
exit 0
}

list () {
s="$(awk -F "\t" -v t="$1" '$2 == t { print }' $TODOFILE)"
if [ -z "$s" ]
then
echo >&2 "No such context."
exit 1
fi

awk -v s="$1" '
BEGIN {
FS = "\t"
print
}
$2 == s {
print $1
}
END {
print ""
}
' $TODOFILE
exit 0
}

search () {
s="$(grep -E $1 $TODOFILE)"
if [ -z "$s" ]
then
exit 1
else
echo
echo "$s"
echo
exit 0
fi
}

usage () {
printf >&2 "Usage: ${0##*/} -a | -d <regex> | -e <sed command> | -h | -l "
echo >&2 "<context> | -s <regex>]"
echo >&2 "Type \`${0##*/} -h' for more information."
exit 1
}

if [ -f "$TODOFILE" ]
then
while getopts acd:e:hl:s: i
do
case "$i" in
a) add;;
c) contexts;;
d) delete "$OPTARG";;
e) edit "$OPTARG";;
h) help;;
l) list "$OPTARG";;
s) search "$OPTARG";;
?) usage;;
esac
done
usage
else
echo >&2 "No such file: $TODOFILE"
exit 1
fi

.



Relevant Pages

  • Re: Command Script variable value lost during execution
    ... the command prompt after the script exit? ... I also added all those ECHO to follow the logic and as you can see in the ... a system but the value of the variable is lost during execution and it get back it's value when exiting the script like if I was using SETLOCAL but I don't use it... ... :: Check the version of RoboCopy from the Date ...
    (microsoft.public.windows.server.scripting)
  • Re: [SLE] Setting a script to automatically download a file from nai.com ftp site?
    ... You will need to put it in a script file and run it from cron. ... echo "Retrieving update list" ... echo "downloading $FTPDIR$DATNAME - please wait" ...
    (SuSE)
  • Re: Bash script Slack >> Deb-Etch
    ... echo>> ~/.signature ... -wF chokes cut, and the switch isn't ... Somehow in the script ...
    (comp.os.linux.misc)
  • Re: Newbie Three
    ... echo "tesgform"; ... echo "suspected alien invasion case topic table"; ... echo "suspected alien invasion unknown group name"; ...
    (comp.lang.php)
  • Newbie Three
    ... echo "tesgform"; ... echo "suspected alien invasion case topic table"; ... echo "suspected alien invasion unknown group name"; ...
    (comp.lang.php)