Shell config subfiles

Large shell startup scripts (.bashrc, .profile) over about fifty lines or so with a lot of options, aliases, custom functions, and similar tweaks can get cumbersome to manage over time, and if you keep your dotfiles under version control it’s not terribly helpful to see large sets of commits just editing the one file when it could be more instructive if broken up into files by section.

Given that shell configuration is just shell code, we can apply the source builtin (or the . builtin for POSIX sh) to load several files at the end of a .bashrc, for example:

source ~/.bashrc.options
source ~/.bashrc.aliases
source ~/.bashrc.functions

This is a better approach, but it still binds us into using those filenames; we still have to edit the ~/.bashrc file if we want to rename them, or remove them, or add new ones.

Fortunately, UNIX-like systems have a common convention for this, the .d directory suffix, in which sections of configuration can be stored to be read by a main configuration file dynamically. In our case, we can create a new directory ~/.bashrc.d:

$ ls ~/.bashrc.d
options.bash
aliases.bash
functions.bash

With a slightly more advanced snippet at the end of ~/.bashrc, we can then load every file with the suffix .bash in this directory:

# Load any supplementary scripts
for config in "$HOME"/.bashrc.d/*.bash ; do
    source "$config"
done
unset -v config

Note that we unset the config variable after we’re done, otherwise it’ll be in the namespace of our shell where we don’t need it. You may also wish to check for the existence of the ~/.bashrc.d directory, check there’s at least one matching file inside it, or check that the file is readable before attempting to source it, depending on your preference.

The same method can be applied with .profile to load all scripts with the suffix .sh in ~/.profile.d, if we want to write in POSIX sh, with some slightly different syntax:

# Load any supplementary scripts
for config in "$HOME"/.profile.d/*.sh ; do
    . "$config"
done
unset -v config

Another advantage of this method is that if you have your dotfiles under version control, you can arrange to add extra snippets on a per-machine basis unversioned, without having to update your .bashrc file.

Here’s my implementation of the above method, for both .bashrc and .profile:

PuTTY configuration

PuTTY is a terminal emulator with a free software license, including an SSH client. While it has cross-platform ports, it’s used most frequently on Windows systems, because they otherwise lack a built-in terminal emulator that interoperates well with Unix-style TTY systems.

While it’s very popular and useful, PuTTY’s defaults are quite old, and are chosen for compatibility reasons rather than to take advantage of all the features of a more complete terminal emulator. For new users, this is likely an advantage as it can avoid confusion, but more advanced users who need to use a Windows client to connect to a modern GNU/Linux system may find the defaults frustrating, particularly when connecting to a more capable and custom-configured server.

Here are a few of the problems with the default configuration:

  • It identifies itself as an xterm(1), when terminfo(5) definitions are available named putty and putty-256color, which more precisely define what the terminal can and cannot do, and their various custom escape sequences.
  • It only allows 16 colors, where most modern terminals are capable of using 256; this is partly tied into the terminal type definition.
  • It doesn’t use UTF-8 by default, which should be used whenever possible for reasons of interoperability and compatibility, and is well-supported by modern locale definitions on GNU/Linux.
  • It uses Courier New, a workable but rather harsh monospace font, which should be swapped out for something more modern if available.
  • It uses audible terminal bells, which tend to be annoying.
  • Its default palette based on xterm(1) is rather garish and harsh; softer colors are more pleasant to read.

All of these things are fixable.

Terminal type

Usually the most important thing in getting a terminal working smoothly is to make sure it identifies itself correctly to the machine to which it’s connecting, using an appropriate $TERM string. By default, PuTTY identifies itself as an xterm(1) terminal emulator, which most systems will support.

However, there’s a terminfo(5) definition for putty and putty-256color available as part of ncurses, and if you have it available on your system then you should use it, as it slightly more precisely describes the features available to PuTTY as a terminal emulator.

You can check that you have the appropriate terminfo(5) definition installed by looking in /usr/share/terminfo/p:

$ ls -1 /usr/share/terminfo/p/putty*
/usr/share/terminfo/p/putty  
/usr/share/terminfo/p/putty-256color  
/usr/share/terminfo/p/putty-sco  
/usr/share/terminfo/p/putty-vt100

On Debian and Ubuntu systems, these files can be installed with:

# apt-get install ncurses-term

If you can’t install the files via your system’s package manager, you can also keep a private repository of terminfo(5) files in your home directory, in a directory called .terminfo:

$ ls -1 $HOME/.terminfo/p
putty
putty-256color

Once you have this definition installed, you can instruct PuTTY to identify with that $TERM string in the Connection > Data section:

Correct terminal definition in PuTTY

Here, I’ve used putty-256color; if you don’t need or want a 256 color terminal you could just use putty.

Once connected, make sure that your $TERM string matches what you specified, and hasn’t been mangled by any of your shell or terminal configurations:

$ echo $TERM
putty-256color

Color space

Certain command line applications like Vim and Tmux can take advantage of a full 256 colors in the terminal. If you’d like to use this, set PuTTY’s $TERM string to putty-256color as outlined above, and select Allow terminal to use xterm 256-colour mode in Window > Colours:

256 colours in PuTTY

You can test this is working by using a 256 color application, or by trying out the terminal colours directly in your shell using tput:

$ for ((color = 0; color <= 255; color++)); do
> tput setaf "$color"
> printf "test"
> done

If you see the word test in many different colors, then things are probably working. Type reset to fix your terminal after this:

$ reset

Using UTF-8

If you’re connecting to a modern GNU/Linux system, it’s likely that you’re using a UTF-8 locale. You can check which one by typing locale. In my case, I’m using the en_NZ locale with UTF-8 character encoding:

$ locale
LANG=en_NZ.UTF-8
LANGUAGE=en_NZ:en
LC_CTYPE="en_NZ.UTF-8"
LC_NUMERIC="en_NZ.UTF-8"
LC_TIME="en_NZ.UTF-8"
LC_COLLATE="en_NZ.UTF-8"
LC_MONETARY="en_NZ.UTF-8"
LC_MESSAGES="en_NZ.UTF-8"
LC_PAPER="en_NZ.UTF-8"
LC_NAME="en_NZ.UTF-8"
LC_ADDRESS="en_NZ.UTF-8"
LC_TELEPHONE="en_NZ.UTF-8"
LC_MEASUREMENT="en_NZ.UTF-8"
LC_IDENTIFICATION="en_NZ.UTF-8"
LC_ALL=

If the output of locale does show you’re using a UTF-8 character encoding, then you should configure PuTTY to interpret terminal output using that character set; it can’t detect it automatically (which isn’t PuTTY’s fault; it’s a known hard problem). You do this in the Window > Translation section:

Using UTF-8 encoding in PuTTY

While you’re in this section, it’s best to choose the Use Unicode line drawing code points option as well. Line-drawing characters are most likely to work properly with this setting for UTF-8 locales and modern fonts:

Using Unicode line-drawing points in PuTTY

If Unicode and its various encodings is new to you, I highly recommend Joel Spolsky’s classic article about what programmers should know about both.

Fonts

Courier New is a workable monospace font, but modern Windows systems include Consolas, a much nicer terminal font. You can change this in the Window > Appearance section:

Using Consolas font in PuTTY

There’s no reason you can’t use another favourite Bitmap or TrueType font instead once it’s installed on your system; DejaVu Sans Mono, Inconsolata, and Terminus are popular alternatives. I personally favor Ubuntu Mono.

Bells

Terminal bells by default in PuTTY emit the system alert sound. Most people find this annoying; some sort of visual bell tends to be much better if you want to use the bell at all. Configure this in Terminal > Bell:

Using taskbar bell in PuTTY

Given the purpose of the alert is to draw attention to the window, I find that using a flashing taskbar icon works well; I use this to draw my attention to my prompt being displayed after a long task completes, or if someone mentions my name or directly messages me in irssi(1).

Another option is using the Visual bell (flash window) option, but I personally find this even worse than the audible bell.

Default palette

The default colours for PuTTY are rather like those used in xterm(1), and hence rather harsh, particularly if you’re used to the slightly more subdued colorscheme of terminal emulators like gnome-terminal(1), or have customized your palette to something like Solarized.

If you have decimal RGB values for the colours you’d prefer to use, you can enter those in the Window > Colours section, making sure that Use system colours and Attempt to use logical palettes are unchecked:

Defining colorschemes in PuTTY

There are a few other default annoyances in PuTTY, but the above are the ones that seem to annoy advanced users most frequently. Dag Wieers has a similar post with a few more defaults to fix.

Tmux environment variables

The user configuration file for the tmux terminal multiplexer, .tmux.conf, supports defining and using environment variables in the configuration, with the same syntax as most shell script languages:

TERM=screen-256color
set-option -g default-terminal $TERM

This can be useful for any case in which it may be desirable to customise the shell environment when inside tmux, beyond setting variables like default-terminal. However, if you repeat yourself in places in your configuration file, it can also be handy to use them as named constants. An example could be establishing colour schemes:

TMUX_COLOUR_BORDER="colour237"
TMUX_COLOUR_ACTIVE="colour231"
TMUX_COLOUR_INACTIVE="colour16"

set-window-option -g window-status-activity-bg $TMUX_COLOUR_BORDER
set-window-option -g window-status-activity-fg $TMUX_COLOUR_ACTIVE
set-window-option -g window-status-current-format "#[fg=$TMUX_COLOUR_ACTIVE]#I:#W#F"
set-window-option -g window-status-format "#[fg=$TMUX_COLOUR_INACTIVE]#I:#W#F"

The explicit commands to work with environment variables in .tmux.conf are update-environment, set-environment, and show-environment, and are featured in the manual.

Reloading tmux config

If you have made changes to your tmux configuration file in the ~/.tmux.conf file, it shouldn’t be necessary to start the server up again from scratch with kill-server. Instead, you can prompt the current tmux session to reload the configuration with the source-file command.

This can be done either from within tmux, by pressing Ctrl+B and then : to bring up a command prompt, and typing:

:source-file ~/.tmux.conf

Or simply from a shell:

$ tmux source-file ~/.tmux.conf

This should apply your changes to the running tmux server without affecting the sessions or windows within them.

Debugging Vim setup

While Vim’s core is very stable, problems can come about when extending the editor with plugins, particularly if there are a high number of them or if they’re buggy or not very well written. While Vim offers a number of ways to keep scripts’ behaviours isolated from one another, it may happen that you find Vim behaving in an unexpected way that you can’t quite pin down. There are a few very good approaches to figuring this out.

List your scripts

First of all, it helps to get a handle on what exactly you’ve got loaded during your Vim sessions. You can do this with the :scriptnames command:

:scriptnames
1: /usr/share/vim/vimrc
2: /usr/share/vim/vim73/debian.vim
3: ~/.vimrc
4: ~/.dotfiles/vim/autoload/pathogen.vim
...

This list appears in the order in which the files were loaded, which might give you a starting point for figuring out where the problem lies.

Update your plugins

Check the documentation, release logs, known problems, and in particular the website of your chosen plugins to see if there are any recent updates to them. If they’re hosted on GitHub, pull down the most recent versions.

Start with no plugins

You can start Vim with no plugins, in a pristine state that doesn’t source any vimrc files from your system or home directories, to figure out if the behaviour you’re observing still occurs with no plugins at all installed. This is done by calling Vim with the -u and -U options, which normally specify the path to a custom location for vimrc and gvimrc files respectively, with the special parameter of NONE:

$ vim -u NONE -U NONE

Vim will open and you’ll see the usual blue tildes for opening a line and Vim’s opening splash screen, having completely ignored your laborious setup.

This done, you can source plugins individually until you notice the problem starts happening, by a process of elimination:

:so plugin/fugitive.vim
:so plugin/unimpaired.vim
:so plugin/badplugin.vim

Profile startup time

If Vim was compiled with the +startuptime feature, you can also pass the --startuptime flag to it with a filename argument, and it will save a verbose log of its startup procedure to that file for you to inspect:

$ vim +q --startuptime startuptime.txt
$ vim startuptime.txt

There’s way more information in here than you’re ever likely to need, but in the case of a buggy setup or unacceptably slow startup time, it’s very useful for diagnosing the bottleneck in your setup.