Tuesday, June 7, 2011

TODO list for console (bash, python, perl)

Another script from my console-based scripts. It is very useful and simple. I use it with conky. Basicaly it is a very simple list of tasks, notes, TODOs, etc.


This script creates file todo_list where all notes are stored. Path to this file is specified at the begin of the script in variable LIST.

I'm using it with CONKY, here's the line from .conkyrc:
${font}${color #00AA00}Todo List ${hr}
${color #00FF00}${execi 5 todo show}
Here's a screenshot from conky:


USAGE: script accepts several parameters: add, rem, down, up and help.
To list all notes type: todo.
To add entry type: todo add this is my note, to remove one note: rem 2 (where 2 is the line number showed with todo). With numbers you can use parameters up and down, whose are for moving the notes at the top or bottom.
I have this script in ~/bin folder, where also todo_list file is created.
NOTE: you can create aliases for more comfortable script usage:
  alias add="todo add"
  alias rem="todo rem"
  alias down="todo down"
  alias up="todo up"

The bash script:
#!/bin/bash

LIST=~/bin/todo_list

#specific options need to be tested to prevent errors
if [ "x$1" == "xrem" ] || [ "x$1" == "xdown" ] || [ "x$1" == "xup" ]; then
 expr $2 + 1 2>/dev/null 1>2;
 #test if return statement from previous command was succesfull 
 if [ $? -ne 0 ]; then echo Invalid number \'$2\'; exit 0; fi
 if [ "x$2" == "x" ] || [ "$2" -le 0 ] || [ "$2" -gt "`cat $LIST | grep -c ""`" ]; then
  echo Invalid parameter or incorrect line number. Use \'todo help\' for help.; 
  exit 1
 fi
fi

case "$1" in
 "add" )  echo Added: `echo $@ | sed -e 's/add //'`
    echo $@ | sed -e 's/add //' >> $LIST;;

  "rem" )  echo Removed: `awk NR==$2 $LIST`
    sed -i $2d $LIST;;

 "down" ) echo Moved: `awk NR==$2 $LIST`
    awk NR==$2 $LIST >> $LIST
    sed -i $2d $LIST;;

 "up" )  echo Moved: `awk NR==$2 $LIST`
    awk NR==$2 $LIST >> $LIST
    sed -i $2d $LIST
    SUM=`cat $LIST | grep -c ""`
    i=1
    until [ $i -ge $SUM ]; do
    awk NR==1 $LIST >> $LIST
    sed -i 1d $LIST
    i=$(($i+1))
    done;;


 "help" )    echo ""
                echo "KrisKo 2010" 
                echo ""
                echo "Usage: todo [OPTION]"
                echo ""
                echo "Script accepts following options:"
                echo "show      show todo list"
                echo "add       add entry to todo list"
    echo "rem #nr   remove entry from todo list" 
    echo "down #nr  move entry from todo list to the bottom" 
    echo "up #nr    move entry from todo list to the top" 
                echo "";;

 * )   cat $LIST | grep -n "" | sed -e 's/:/: /';;

esac

exit 0
NOTE: beware of using the symbols $, #, >, < etc. They have special usage in bash and they won't be added correctly into the todo_list file, they could even remove/overwrite this file!
NOTE: in the above script example is > symbol represented as $gt;.

Here's the script in python:
#!/usr/bin/python

import sys
import commands

LIST="/home/krisko/bin/todo_list"

def help():  
    print "KrisKo 2011\n"  
    print "Usage: todo [OPTION]\n"  
    print "Script accepts following options:"  
    print "show\t\tshow todo list"  
    print "add\t\tadd entry to todo list"  
    print "rem #nr\t\tremove entry from todo list"  
    print "down #nr\tmove entry from todo list to the bottom"  
    print "up #nr\t\tmove entry from todo list to the top\n"  

def openfile():
    f = open(LIST, "r")
    content = f.readlines()
    f.close()
    return content

def writefile(content):
    f = open(LIST, "w")
    f.writelines(content)
    f.close()

def edit():
    if (sys.argv[1] == "rem"):
        content=openfile()
        sys.stdout.write("Removed: " + content[int(sys.argv[2])-1])
        del content[int(sys.argv[2])-1]
        writefile(content)
    elif (sys.argv[1] == "down"):
        content=openfile()
        sys.stdout.write("Moved: " + content[int(sys.argv[2])-1])
        content.append(content[int(sys.argv[2])-1])
        del content[int(sys.argv[2])-1]
        writefile(content)
    elif (sys.argv[1] == "up"):
        content=openfile()
        sys.stdout.write("Moved: " + content[int(sys.argv[2])-1])
        content.insert(0, content[int(sys.argv[2])-1])
        del content[int(sys.argv[2])]
        writefile(content)
    else:
        print "ERROR!"
        exit (1)

if (len(sys.argv) > 2) and (sys.argv[1] != "add"): 
    if (sys.argv[1] == "rem" ) or (sys.argv[1] == "down") or (sys.argv[1] == "up"):
        if (sys.argv[2].isdigit()) and (int(sys.argv[2]) <= int(commands.getoutput("cat " + LIST + " | grep -c \"\""))) and (int(sys.argv[2]) != int(0)):
            edit()
        else:
            print "Invalid parameter or incorrect line number. Use \'todo help\' for help."
    else:
        print "Invalid parameter!"
elif (len(sys.argv) > 1):
    if(sys.argv[1] == "help"):
        help()
    elif(sys.argv[1] == "show"):
        print commands.getoutput("cat " + LIST + " | grep -n \"\" | sed -e 's/:/: /'")
    elif(sys.argv[1] == "add"):
        ARGPOS=2
        ARG=""
        while ARGPOS < len(sys.argv):
            ARG=ARG + sys.argv[ARGPOS] + " "
            ARGPOS += 1
        with open(LIST, "a") as f:
            f.write(ARG + "\n")
        f.close()
        print "Added: " + ARG
    else:
        print "Unknown parameter specified or line number is missing. Use \'todo help\' for help.;"
else:
    print commands.getoutput("cat " + LIST + " | grep -n \"\" | sed -e 's/:/: /'")
    exit (1)
And the script in perl:
#!/usr/bin/perl

$LIST="/home/krisko/bin/todo_list";

sub help{ 
 print "\nKrisKo 2011\n"; 
 print "\nUsage: todo [OPTION]\n";
 print "\nScript accepts following options:\n";
 print "show\t\tshow todo list\n";
 print "add\t\tadd entry to todo list\n";
 print "rem #nr\t\tremove entry from todo list\n";
 print "down #nr\tmove entry from todo list to the bottom\n";
 print "up #nr\t\tmove entry from todo list to the top\n\n";
 exit 0;
}

sub edit{
 open(LIST, $LIST) || die ("Cannot open input file.\n");
 @stored = <LIST>;
 if ("$ARGV[0]" eq "rem"){
  print ("Removed: $stored[$ARGV[1]-1]");
  delete $stored[$ARGV[1]-1];
 } elsif ("$ARGV[0]" eq "down"){
  @stored = (@stored, $stored[$ARGV[1]-1]);
  print ("Moved: $stored[$ARGV[1]-1]");
  delete $stored[$ARGV[1]-1];
 } elsif ("$ARGV[0]" eq "up"){
  @stored = ($stored[$ARGV[1]-1], @stored);
    print ("Moved: $stored[$ARGV[1]]");
    delete $stored[$ARGV[1]];
 }
 open(LIST, ">$LIST") || die ("Cannot open input file.\n");
 print LIST (@stored);
exit 0;
}

#open todo list file or die
open(LIST, $LIST) || die ("Cannot open input file.\n");

#arguments count
$ARGS = @ARGV;
#todo list lines count
$count++ while <LIST>;

if ("$ARGV[0]" eq "help"){
help();
}

if (($ARGS > 0) && ("$ARGV[0]" ne "add")){
 if (("$ARGV[0]" eq "rem") || ("$ARGV[0]" eq "down") || ("$ARGV[0]" eq "up")){
  if (($ARGV[1] > 0) && ($ARGV[1] <= $count)){
   edit();
   exit 0;
  } else {
   printf "Invalid parameter or incorrect line number. Use \'todo help\' for help.\n";
   exit 1;
  }
 }
 else {
  printf "Invalid parameter!\n";
  exit 1;
 }
}

if (("$ARGV[0]" eq "show") || ($ARGS == 0)){
 open(LIST, $LIST) || die ("Cannot open input file.\n");
 $counter=1;
 while ($inputline = <LIST>) {
   print ($counter,": ", $inputline);
  $counter++;
 }
 exit 0;
}

if ("$ARGV[0]" eq "add" && $ARGV[1]){
 open(ADD, ">>$LIST") || die ("Cannot open input file.\n");
 printf "Added: ";
 foreach $arc (1 .. $ARGS) {
  print ADD ("$ARGV[$arc] ");
  print ("$ARGV[$arc] ");
 }
 print ADD ("\n");
 print ("\n");
 exit 0;
} else {
 print ("Trying to add empty line?\n");
 exit 1;
}

print "Unknown parameter specified or line number is missing. Use \'todo help\' for help.\n";
exit 1;

2 comments:

  1. Your todo script is great! Thank you for sharing!

    ReplyDelete
  2. I love it. I thought of writing some script in bash , but yours works as expected. Thanks for your bash script to-do all my task day-to-day. A handy task manager.

    Thanks,
    Kesavan Muthuvel
    kesavan.info

    ReplyDelete