Move to any of 62 directories in 3 keystrokes

I saw a discussion of this in
http://unix.stackexchange.com/questions/1906/direct-command-line-into-a-specified-directory

To get a list of commonly-used directories, put this in ~/.bashrc:

    # track directories used.
    cd () {
        builtin cd "$@"
        /bin/pwd >> ~/.bashdir.new
    }

After a week or so, run this:

    me% cd
    me% sort .bashdir.new | uniq -c | sort -n > .bashdir.common

The .bashdir.common file might look like this after you keep just the directories you use the most often:

     20 /usr/local/src
     20 /var/adm/sa/perflog
     21 /backup/today
     23 /tmp
     24 /data01
     24 /data02
     24 /data03
     24 /data04
     24 /data05
     24 /data06
     24 /data07
     24 /data08
     27 /home/yourname/projects
     28 /doc/templates
     28 /doc/html
     32 /var/log/samba
     35 /usr/local/cron
     35 /usr/local/lib
     35 /usr/local/bin

Make your quick-change list:

    me% mkcdlist .bashdir.common > .bashdir

    me% cat .bashdir
    0   /usr/local/src
    1   /var/adm/sa/perflog
    2   /backup/today
    3   /tmp
    4   /data01
    5   /data02
    6   /data03
    7   /data04
    8   /data05
    9   /data06
    a   /data07
    b   /data08
    c   /home/yourname/projects
    d   /doc/templates
    e   /doc/html
    f   /var/log/samba
    g   /usr/local/cron
    h   /usr/local/lib
    i   /usr/local/bin

mkcdlist script:
    #!/bin/ksh
    #<mkcdlist: read up to 36 common directories, write a list for g.

    t1=/tmp/cd1$$
    t2=/tmp/cd2$$
    num='0 1 2 3 4 5 6 7 8 9'
    let='a b c d e f g h i j k l m n o p q r s t u v w x y z'
    max=36

    # Make sure we have a file to read...
    case "$#" in
        1) file=$1 ;;
        *) echo no file; exit 0 ;;
    esac

    # ... and that it doesn't have more lines than we have letters.
    set X $(wc -l $file)
    lines=$2
    test "$lines" -gt $max && {
        echo $file has more than $max lines, please trim it; exit 1 ;
    }

    # Write unique number/letter for each directory.
    echo "$num $let" | fmt -1 | head -$lines > $t1
    expand $file | sed -e 's!^.* /!/!' > $t2
    paste $t1 $t2 | expand -4
    echo

    rm $t1 $t2
    exit 0

You'll be able to get to any one of those directories in three keystrokes if you have a single letter available for use as an alias. I use "g":
    g CR number-or-letter

You'll see your directory list. Press one letter or number and you immediately change to that directory.

You'll need a program called "grabchars", which you can find on a comp.sources.misc archive or by using http://www.filewatcher.com/. Grabchars lets you handle single-character feedback in a portable fashion via command line or shell-script. For example, running

    grabchars -c 0123456789 -n2 -t10

interactively reads two numbers with a ten-second timeout, no need to press return after the numbers.

    [ Section on installation of grabchars ]

Original shell function for no more than 36 directories:
    g () {
      clear
      cat $HOME/.bashdir
      local prompt="dir: "
      local ans=`grabchars -d0 -L -c '[0-9a-zA-Z]' -q"$prompt"`
      set X `grep "^$ans" $HOME/.bashdir`
      case "$#" in
        (3) cd $3 ;;
        (*) echo no such entry ;;
      esac
    }

If you have a lot more directories to keep track of, try this version:
    g () {
      clear
      cat $HOME/.bashdir2
      local prompt="dir: "
      local ans=`grabchars -d- -c '[0-9a-zA-Z]' -q"$prompt"`
      case "$ans" in
        (-) return ;;
        (*)  ;;
      esac

      set X `fmt -1 $HOME/.bashdir | fgrep "${ans}=" | tr "=" " "`
      case "$#" in
        (3) cd $3 && ( echo; echo; pwd; echo;
            ls -F --color=always -blptF --time-style='+%d-%b-%Y %T' |
                sed -e '/^total/d') ;;
        (*) echo no such entry ;;
      esac
    }

Contents of ~/.bashdir2:
                            Popular directories

 0=/etc                   l=/etc/hp                G=/etc/reader.conf.d
 1=/etc/X11               m=/etc/httpd             H=/etc/rhgb
 2=/etc/acpi              n=/etc/logrotate.d       I=/etc/rpm
 3=/etc/bluetooth         o=/etc/logwatch          J=/etc/rwtab.d
 4=/etc/cron.daily        p=/etc/lvm               K=/etc/sane.d
 5=/etc/cron.hourly       q=/etc/mail              L=/etc/security
 6=/etc/cron.monthly      r=/etc/modprobe.d        M=/etc/selinux
 7=/etc/cron.weekly       s=/etc/netplug           N=/etc/setuptool.d
 8=/etc/cups              t=/etc/netplug.d         O=/etc/skel
 9=/etc/default           u=/etc/ntp               P=/etc/smrsh
 a=/etc/dev.d             v=/etc/openldap          Q=/etc/sound
 b=/etc/firmware          w=/etc/opt               R=/etc/squid
 c=/etc/fonts             x=/etc/pam.d             S=/etc/ssh
 d=/etc/foomatic          y=/etc/pango             T=/etc/stunnel
 e=/etc/gconf             z=/etc/pcmcia            U=/etc/subversion
 f=/etc/gdm               A=/etc/pki               V=/etc/sysconfig
 g=/etc/ghostscript       B=/etc/pm                W=/etc/udev
 h=/etc/gnome-vfs-2.0     C=/etc/ppp               X=/etc/xdg
 i=/etc/gre.d             D=/etc/profile.d         Y=/etc/xinetd.d
 j=/etc/gtk-2.0           E=/etc/rc.d              Z=/etc/yum
 k=/etc/hal               F=/etc/readahead.d

If you have this many directories, it might be worth your while to use a file-manager like mc or vshnu.


$Revision: 1.5 $
$Date: 2010-10-13 14:31:07-04 $
$UUID: e58400c5-8a64-3d05-81c9-84d484c46ab1 $