Shell configuration

Each time I log on to a system for the first time, I get reminded how accustomed I am to my normal shell environment. There are commands that I use unconsciously many times a minute, and if they don't work I keep getting annoyed at the resulting error messages. So it's never long before I tweak the shell configuration to match my required environment in order to be able to do some work. Some shells don't require many changes (sh, ksh), while others need a lot of persuasion before they behave in a remotely sane way (bash).

Everything used to be very simple: each user had a .profile that was executed once every time they logged in. It was the place to lift your spirits with an amusing message, be let down by a calendar of the day's events in history, and set up environment variables for the day's work that all the child processes could inherit.

It was not a good place to set up shell functions, aliases etc. because as soon as a child shell was spawned (from inside an editor or by opening a new terminal window), those settings would be forgotten. That's where the environment variable ENV came in: if it contains a file name, this file gets executed each time a shell process starts (and after .profile is finished). It follows from the above that each child shell that inherits the login shell's environment will run the contents of this file. It is therefore the perfect place to set up shell functions, aliases etc. that should always be available. As an added bonus a user becoming a different user (for example by using su) can take their shell configuration with them unless they explicitly reset their environment variables.

In an environment like this, my .profile usually looks like this:

PATH=$HOME/bin:$PATH

export EDITOR=vi
export PAGER=more

# To shut up perl when gdm has set LANG=de_DE.UTF-8:
export LC_COLLATE=C
export LC_NUMERIC=C

ulimit -p 320 # -j8 compiles may fail with the default -p 160

export ENV=$HOME/.shrc
This sets up my favourite editor and pager. On GNU systems, more tends to be terminally feature-starved, while less is unable to show short files without clearing the entire screen and requires an extra keystroke. While "less -E" gets rid of the last problem, clearing the screen on terminals that support it means you cannot see short files at all -- in which case "less -EX" is actually needed to emulate more's time-tested standard behaviour.

The locale variables get around limitations of NetBSD's implementation that upset Perl in particular. The last line specifies that I would like for the file .shrc in my home directory to be read by every shell instance.

The .shrc file usually contains something like the following:

ps1="$PS1"
if [ -f /etc/shrc ]; then
        . /etc/shrc
fi

case "$-" in *i*)
        # interactive mode settings go here
        cd() { command cd "$@" && PS1="${USER}@${HOST%%.*}:${PWD##*?/}$ps1"; }
        PS1="${USER}@${HOST%%.*}:${PWD##*?/}$ps1"
        set -o vi
        alias ls='ls -F'
        alias la='ls -a'
        alias ll='la -l'
        alias ..='cd ..'
        alias m="$PAGER"
        alias hd='hexdump -C'
        ;;
esac
In it I first save the shell's prompt, then run the system's shrc file (only on machines on which I don't object to the contents). If the shell is interactive (as indicated by the occurrence of the letter 'i' in $-), I lastly set command line editing to vi-mode, configure some aliases and define a cd() function that displays the current directory in the shell prompt.

Unfortunately, these perfectly simple and reasonable mechanisms were not considered adequate by some, who created shells with much more elaborate, intricate startup behaviours. Coercing such shells to support this simple scheme faithfully requires implementing a number of files that get executed and ignored at times which are so impenetrably documented that it is best left to experimentation.

Comments