Sunday, June 17, 2012

User-wide path storage utility

When I work with multiple terminals I often run into inconvenience of having to copy complicated file paths between terminal windows. Also sometimes I wander into deep and hard to remember directory paths and want to save these locations for later use. There is this pushd/popd directory stack in bash, but it is very limited, since its operation is based on environmental variable.

Last night I wrote a small shell utility to save and optionally label directory paths for later use (Download savedir from github, scroll down for installation instructions).


There are two commands:
  • savedir – for saving new paths
  • memdir – for retrieving previously saved paths
By default savedir saves current working directory, but you can also supply (multiple) paths as arguments. All paths are normalized to absolute paths. To print last saved path you have to use memdir. Here's an example of copying files from working directory in terminal 2 to working directory in terminal 1:
Terminal 1:
$ savedir
Terminal 2:
$ cp * `memdir`

To print path saved before the last one just call memdir 1 (one for one step into the past), for one before that call memdir 2, and so on.

To stick a label to some path just use parameter -l label:
$ savedir -l projectx some/long/relative/path/to/project

Now to print that path use memdir -l projectx or just memdir projectx (if argument to memdir is not a number it is considered to be a label). You can stick same label to many paths. memdir -l label always prints last saved directory with that label. To print second last use memdir -l label 1, like when you access paths without a label. Actually paths without a label all share the same label "" (empty string). To print all paths with a label use parameter -a (a for all). To print all saved paths along with associated labels use memdir -av (v for verbose).

To jump to the saved directory you would write cd `memdir` and to change directory to one labeled projectx you would have to use cd `memdir projectx`. But I find it not elegant. I would rather have special command for that. Unfortunately for directory change to have an effect on current shell it can't be done from another process. That's why I used a small workaround for my bash. First I created short script (named ~/bin/memdircd):
target=`memdir $*`
if [ -n "$target" ] ; then
        cd "$target"

Then I added this line to ~/.bashrc:
alias cdmem='. /home/rudy/bin/memdircd'
So now to change directory last saved with savedir I just write cdmem. And for changing directory to one with label projectx you can simply call cdmem projectx.

memdir also can remove paths from its memory. Argument -C (uppercase 'C') is for clearing all paths without any label (that is with label ""), or when used in combination with -l label only those with particular label. Another argument -c number (lowercase 'c') is similar, but leaves specified number of last paths (-c 0 is synonymous to -C).


You can download this utility from github. It is written in python and uses sqlite3 for storage. It's a single script for two commands. To use these commands you have to create two symbolic links named memdir and savedir to this script file, preferably on your $PATH:
$ chmod +x /path/to/script/
$ ln -s /path/to/script/ savedir 
$ ln -s /path/to/script/ memdir


This script will create directory named .savedir in your home directory and store there a file named dirs.sqlite.
Also this software is in very experimental stage, you are very welcome to contribute.