ONLamp.com
oreilly.comSafari Books Online.Conferences.

advertisement


Theming Bash

by Shlomi Fish
02/02/2006

I once wrote in my weblog that just as the number of items on an open source project's to-do list always grows or remains constant, so does the number of projects an open source developer is involved in. Add to that the fact that successful open source projects eventually tend to spawn sub-projects, and you'll see that typical eclectic open-source developers have to deal with a large number of projects and sub-projects.

This is not peculiar to open source developers. Often, people working on software in software shops face similar problems, as do non-programmers such as writers or web designers who work on more than one piece simultaneously, or have to maintain older projects.

The only problem is that we normally only have one computer, and work on one shell account. The purpose of shell "themes" is to make it easy to work on several projects inside of one shell.

What Are Shell Themes?

Shell themes are shell presets that, when invoked, customize the shell with various useful commands for working on a specific project. For example, I can type Theme perl/nav-menu, and then gain some shell commands that are useful for working on my navigation menu module. Among other things, it will also automatically change my directory to ~/progs/perl/www/Nav-Menu/trunk/module/, where I work on the module.

Setting Up the Themes' Infrastructure

Before you can write shell themes, you need to implement an infrastructure for creating them. I keep the logic of the themes in one directory, $HOME/conf/Bash/Themes. To set them up, fetch my Bash themes archive and unpack it under $HOME/conf/Bash or wherever is convenient for you.

Then add the following line to your .bashrc:

. $HOME/conf/Bash/Themes/Source-Me.bash

(Replace $HOME/conf/Bash with the directory in which you placed the Bash themes.)

What do these files do? First, the Source-Me.bash file contains:

__themes_dir="$(dirname $BASH_SOURCE[-1])"

function load_common
{
    source "${__themes_dir}/common/$1.bash"
}

function Theme
{
    local filename

    __theme="$1"
    shift;

    filename="${__themes_dir}/themes/$__theme/source.bash"
    test -e "$filename" || { echo "Unknown theme" 1>&2 ; return 1; }
    source "$filename"
}

complete -W "$(cat ${__themes_dir}/list-of-themes.txt)" Theme

The __themes_dir is a global variable that contains the path to the directory containing the themes (as determined by the path of the Source-Me.bash file). The general convention inside of my Bash themes is that the names of private variables or functions begin with two underscores (as inspired by the C and Python conventions).

load_common() is a utility function that simply "sources" a common library from the themes directory. Individual themes use it to include common pieces of code. The Theme() function is more important. It includes the source file of the theme selected as an argument into the current running process.

Finally, the complete -W command enables sure one can use command line completion on the list of themes after the Theme command. So I can, for example type "Theme " (with a space), press Tab twice, and get a list of themes. Alternatively, I can type the beginning of a theme's name and press Tab to complete it.

The themes go inside of the themes sub-directory in separate directories, where the identifier of each theme is the path in which it resides. Each theme contains a source.bash file that the shell sources.

Note that the __theme variable is not a local one, so the user or other scripts can determine the current theme later on.

Another part of the themes' infrastructure distribution is the gen_list.sh file. Run it whenever you add a new theme or remove an old theme. It contains:

#!/bin/bash

(
    find themes -type d -exec test -e {}/source.bash \; -print |
        sed 's!themes/!!' |
        sort
) > list-of-themes.txt

As you can see, gen_list.sh prepares a sorted list of all the sub-directories of the themes directory that contain the source.bash and places them inside of the file list-of-themes.txt. This file is necessary to enable theme completion for the Theme command.

Examples of Theme Contents

What can you do with themes? Plenty.

Pre-Defined Directories

Almost all of my themes have something like this at their beginning:

base="$HOME/progs/perl/www/Nav-Menu/"
trunk="$base/trunk"
this="$trunk/module"
rw_repos_url="svn+ssh://svn.berlios.de/svnroot/repos/web-cpan/nav-menu"
read_repos_url="svn://svn.berlios.de/web-cpan/nav-menu"
test_dir="$trunk/tests/integration/sites-gen"

These are definitions of directories and Subversion URLs. $this is the default directory, but there are other useful directories. To cd there I can type something like cd $this or cd $trunk.

Because of that, the themes end with the command:

cd $this

Why do I keep such declarations in my themes? Otherwise, all of them will clutter the .bashrc file and also require a lot of namespace-collision prevention, which will in turn make them quite long. Putting them in a theme ensures they are short, the same across all themes, and also that they are only present when I need them.

Theme-Specific Environment Variables

Another good use of themes is to define theme-specific environment variables such as the CVSROOT environment variable, extra PATH elements, and also application-specific environment variables, with which you don't want to clutter the .bashrc, or that vary from theme to theme.

Learning the bash Shell

Related Reading

Learning the bash Shell
Unix Shell Programming
By Cameron Newham, Bill Rosenblatt

Pages: 1, 2

Next Pagearrow





Sponsored by: