GOTO considered useful!!

(Far be it from me to go head to head against Prof. Dijkstra but when I sent this to Stijn (who maintains apparix), he came up with this very cute title, which I promptly stole!)

Despite the title, this is nothing to do with programming, structured or otherwise :-)

This is all about supplementing the lowly cd command with some extra punch for those of us who spend a lot of time at the Linux command line working with files in various directories. Even with bash completion, typing out long directory paths is a chore that kills productivity.

This document has the following sections:

    GOTO considered useful!!
            First, a word about apparix
            What is goto and where do I get it?
            Features and uses
            Usage messages

First, a word about apparix

Like in almost all things in this world, the 80-20 rule applies. For the 20% of directories in which you spend 80% of your time, use the afore-mentioned apparix. For those cases, there's no substitute for the speed with which apparix works, the ability to set short names as bookmarks and to just say

        to wh

instead of

        cd /var/www/homepages/sitaram

The fact that setting bookmarks is just as easy also helps:

        cd /home/sitaram/workdata/mindmaps
        bm mm

bm and to are bash aliases that come with apparix. bm stands for bookmark.

What is goto and where do I get it?

For the other 80% directories where you spend 20% of the time, (and very cleverly, this can also be construed to mean "directories on other machines where you don't spend much time or you don't want to install apparix"!), use goto.

Get it from bashrc.goto and include it in your normal .bashrc

You get three bash functions: goto, fgoto, and goto_range. All of them will respond with a nice usage message if you give -h as the argument. Note that fgoto is really goto in disguise, but the argument is considered to be a file name pattern rather than a directory name pattern.

Features and uses

"Bang for the buck"

goto allows you to get some pretty major productivity gains very quickly, without having to install any software.

Exploring the file system made easy

goto and fgoto make it easy to explore the filesystem looking for stuff whose location you only vaguely remember or guess.

Also, fgoto's ability to jump into a directory based on giving a filename (as opposed to a directory name) is unique. [If you know of other tools which do this, please let me know and I will be happy to acknowledge them; I haven't heard of any so far.]

When you know a good part of the file name, but are not sure where it lives, try fgoto. You'll be surprised!

Quickly set a range for the searches

Sometimes "goto" returns results from directories you don't care about, and you want to restrict the searches to a set of directories only. And sometimes it's the opposite – you want the results coming from anywhere except a certain set of directories.

Use the goto_range command for all this. The -h option shows you a pretty good help message.

This can be very useful sometimes. Ever inherited a whole bunch of files from someone else? Or downloaded a large-ish source tree with many directories and wanted to quickly jump around just within that, looking for files and directories?

Even more quickly set a temporary range

Use goto . some_dir_pattern or fgoto . some_file_pattern to temporarily set the search range to the current directory before doing the goto/fgoto. When invoked this way, the current search range and all related settings are ignored.

In place of . (dot) above, you can use .., ~, or indeed any valid directory name, and you'll get matches only within that directory.


Usage messages

If you're curious, here're examples of the usage messages of the two functions goto and goto_range.


        [sitaram@home ~]$ goto -h
        Usage: goto dir_pattern
               fgoto file_pattern

        Uses the locate database to find a directory (i) matching the dir_pattern OR
        (ii) containing a file matching the file_pattern

        The patterns use locate's "-r" option, except that we're only interested in
        matching the last component of each candidate path.

        argument        matches what part of last path component?
        ------------    -----------------------------------------
        path            anywhere
        /path           starts with
        path$           ends with
        /path$          exact

        IMPORTANT: You can restrict the search to one or more directories.  Run
        "goto_range -h" to learn how to use the search range effectively.

        SHORTCUT: "goto . pattern" or "fgoto . pattern" TEMPORARILY sets the search
        range to the current directory and then does the goto/fgoto, REGARDLESS of
        what the current range settings are!  You can do this with any directory
        instead of "." -- I usually do this to ".", "..", "~", "/var" etc., as needed.


        [sitaram@home ~]$ goto_range -h
        Usage: goto_range s|a|l|u|e|i

        Sometimes "goto" returns results from directories you don't care about, and
        you want to restrict the searches to a set of directories only

          s = SET the current directory as the search range
          a = ADD the current directory to the search range

          l = LIMIT searches to the search range
              the search range is set to the current directory if it is undefined
              using the "s" or the "a" option automatically sets this also
          u = UNlimited; use the entire locate database
              the search range is not used even if it is defined
              this is the default behaviour

        Sometimes you want to say "search everywhere except in these directories"

          e = EXCLUDE directories; search everywhere EXCEPT in search range
          i = INCLUDE directories; search only in search range
              this is the default behaviour


Here's how a few typical interactions might look like:

        [sitaram@home ~]$ goto 6-misc-set2

        [sitaram@home ~]$ fgoto img_2178

        [sitaram@home ~]$ fgoto img_1878
         1) /home/sitaram/save/pictures/mine/2005-friends
         2) /home/sitaram/save/pictures/mine/2005-ganesh
        #? 2

Here's an example where it found multiple matches:

        [sitaram@home ~]$ goto misc-set
        1) /home/sitaram/save/pictures/mine/2006-misc-set1  5) /home/sitaram/save/pictures/mine/2005-misc-set2
        2) /home/sitaram/save/pictures/mine/2006-misc-set2  6) /home/sitaram/save/pictures/mine/2005-misc-set3
        3) /home/sitaram/save/pictures/mine/2006-misc-set3  7) /home/sitaram/save/pictures/mine/2005-misc-set4
        4) /home/sitaram/save/pictures/mine/2005-misc-set1
        #? 3
        [sitaram@home 2006-misc-set3]$

Here's another example where it found multiple matches:

        [sitaram@home ~]$ goto security
         1) /home/sitaram/imli/files-pers/blog/blosxom-stuff/blosxom/software/security
         2) /home/sitaram/.local/share/applications/Mandrakelinux/System/Configuration/KDE/Security
         3) /etc/security
         4) /var/lib/menu-xdg/applications/Mandrakelinux/System/Configuration/KDE/Security
         5) /var/lib/menu-xdg/simplified/applications/Mandrakelinux/AdministerYourSystem/UseMoreAdministrationTools/Configuration/KDE/Security
         6) /var/log/security
         7) /usr/share/doc/HOWTO/HTML/en/Security
         8) /usr/share/doc/HOWTO/HTML/en/Security-Quickstart
         9) /usr/share/doc/HOWTO/HTML/en/Security-Quickstart-Redhat
        10) /usr/share/ri/1.8/system/SecurityError
        11) /usr/lib/libDrakX/security
        12) /usr/lib/nvu-1.0/chrome/en-US/locale/global/security
        #? ^C

Oops – too many matches, and from too many different places. I want to restrict the match to just the home directory. The long way is to use the goto_range command to set a range and then use the goto. The quick way is to just add a valid directory name (in this case just ~) as the first argument.

        [sitaram@home ~]$ goto ~ security
        range status: goto is currently limited
        the range is defined to be
        run "goto_range -h" for usage

        search range:	^/home/sitaram
        1) /home/sitaram/imli/files-pers/blog/blosxom-stuff/blosxom/software/security
        2) /home/sitaram/.local/share/applications/Mandrakelinux/System/Configuration/KDE/Security
        #? 1
        [sitaram@home security]$

Remember: any valid directory is good for this trick, so the most common examples are things like are ., .., /etc, /var/www, etc.