IJ Bash Environment

The IJ Bash Environment is a packaging of part of the way I set up my own bash + xterm environment in Linux. There isn't much code to it, but a little script code can go a long way, and it appears to be sufficiently original to be worth sharing.


There are two components. The first is a little utility program to display a scrollable menu in an xterm or similar terminal emulator, ijmenu (man page). In fact, ijmenu a standalone tool which may be useful in itself as a minimalist alternative to programs like whiptail and dialog. Copy it to any directory in your $PATH, or, for a system-wide install, put it in /usr/bin and generate a man page like this:

pod2man -c "" -r "`ijmenu -v`" `which ijmenu` \
    | gzip -9 > /usr/share/man/man1/ijmenu.1.gz

In operation, it looks like this:

: ~ 15;  man ijmenu
: ~ 16;  ijmenu 1 5 0 zero one two three four five six seven


The rest of the package is in ij.bash. To use this, copy it to (for example) your home directory and add the following line to your ~/.bashrc to source it:

. ij.bash

If you're the system administrator, you can of course put it somewhere like /etc/.

Now a brief run-through of what it does. First, it keeps a record of all directory changes, allowing you to quickly change to previous working directories with the help of ijmenu.

: ~ 1;  pwd
: ~ 2;  cd /usr/lib/perl5/auto/Locale
: Locale 3;  alias sc='cd ~/scripts'
: Locale 4;  sc
: scripts 5;  pushd /var/lib
/var/lib ~/scripts
: lib 6;  d
cd ~
cd /usr/lib/perl5/auto/Locale
cd ~/scripts

Above, 'd' is aliased to the function ij_rd. Note that it doesn't matter what command is used to effect the directory change - whether it be an ordinary cd, an alias or anything else.

The prompt string (bash's PS1) may look strange. It is chosen to allow easy copying and pasting of commands: if you copy a whole line using a mouse triple-click and paste it to repeat the command then the prompt will be ignored by bash - since ':' is a shell builtin command that does nothing, and what follows it, up to the terminating ';', are treated as its arguments.

This is especially useful if you want to copy a command to paste into another terminal, or if you want to copy a series of commands: provided they are not separated by output, you can repeat all the commands by doing a single block copy and paste.

The prompt is kept deliberately short, with the full directory path and the time the prompt appeared being put in the title bar of the terminal window. The time allows you to see the time the last command completed (which can be interesting if you leave a long-running command executing while you go and do something else). More helpfully, together with the directory, it allows you to quickly identify the terminal session you want from a window list:

xterm title prompt

What about PS2? Some indication that the current command is incomplete is needed, but it would preferably be "transparent" like the PS1 prompt, so that a multiline command could be copied and pasted in one block. One approach is to use one or more spaces. This is transparent in most cases, but indents the following lines more on each successive copy and paste. A truly transparent alternative is a colour splash prompt:

: bin 15;  for i in ij*
: bin 15;  for i in ij*
    echo "file: $i"
file: ijmenu
: bin 16; 

I sometimes copy the contents of a terminal (the commands and their output) into a file. This can be a boon for sysadmin-type tasks, for example, to record and so later be able to repeat the necessary configuration steps to install some piece of software without reading through all the documentation again, or for demonstrational purposes, or to report a bug, etc. For this, the "filter terminal session" function preserves lines starting with a prompt unchanged, while turning output into comments. Here's a brief snippet to illustrate (note also the different colour prompt for user root):

: / 15;  cd /etc
: etc 16;  cp fstab fstab.bak
: etc 17;  vi fstab
: etc 18;  # here's what I changed:
: etc 19;  diff fstab.bak fstab
< LABEL=lenny     /               ext3    errors=remount-ro 0       1
> LABEL=squeeze   /               ext3    errors=remount-ro 0       1
: etc 20; 
: etc 20;  fts >> ~/config.log

At this point, the commands up to the "fts" are copied and pasted, and thus passed through fts into the log file. The result is:

: etc 21;  tail ~/config.log
  cd /etc
  cp fstab fstab.bak
  vi fstab
  # here's what I changed:
  diff fstab.bak fstab
# 5c5
# < LABEL=lenny     /               ext3    errors=remount-ro 0       1
# ---
# > LABEL=squeeze   /               ext3    errors=remount-ro 0       1

: etc 22; 

To preserve the prompts on command lines, use "fts -p".

Consistent with the above, "h" is an alias for an alternative to the history function: it wraps the history numbers in the same manner as the prompt, to allow for quick triple-click or block copying of commands into the same or another terminal:

: ~ 23;  h 9
 :  15;  cd /etc             ## cd /etc
 :  16;  cp fstab fstab.bak
 :  17;  vi fstab
 :  18;  # here's what I changed:
 :  19;  diff fstab.bak fstab
 :  20;  fts >> ~/config.log
 :  21;  tail ~/config.log
 :  22;  cd -                ## cd ~
 :  23;  h
: ~ 24; 

Note the extra comments: any command which changes the working directory is highlighted with an extra "## cd ..." so that it's easy to see the directories in which the commands were executed. In fact the directory change mechanism, as currently implemented, gets the directory history from this annotated history output.

In addition to the above, there are functions to save and restore (replay) the working directory history. See the contents of ij.bash for these.


There are some limitations. For example, it is assumed that directory names don't have spaces in them (mine don't), and the "fts" function does not attempt to distinguish the second and subsequent lines of multiline commands from the output of those commands (with an effectively empty PS2 prompt, that would be difficult to do). For me, these issues aren't significant.


Directory changing: Though some swear by Ctrl-R, there seems to be a general consensus that bash's built-in mechanisms for remembering and changing directories are inadequate, and many Linux/Unix shell users have come up with their own approaches to correcting this. Two tools based on the idea of bookmarking directories are Stijn van Dongen's Apparix, one of the more sophisticated alternatives, and cdargs, which additionally provides a full-screen directory browser. Even if you're a bookmarking kind of person, the simple directory-changing functionality described here is to some extent complementary, insofar as it allows you to swap very rapidly within a group of directories you happen to be working in right now without bookmarks or aliases.

History: the annotation of bash's command history to show changes in the working directory is based on Dennis Williamson's solution to a problem posed by Lajos Nagy.

Prompts: Though I haven't seen anyone using the truly empty prompt (above, that's the one I called a "colour splash prompt"), the idea of a PS1 prompt that makes for easy triple-click copy and pasting is relatively well known – see the Bash Prompt HOWTO).

—  Michael Breen, 2011.3.17