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
: