Managing my shell setup
Apologies for not being perl enough in this post .. my working environment is key to me being able to get anything done so I figure it’s a grey area I’m allowed to wander into.
Something I’ve battled with for a long time is how best to manage my bash setup and aliases.
For far too long I’d been copying a .bashrc
or .bash_aliases
file onto each
new box I’m working on, comment out a few parts, fix a few parts, …
As I started having accounts on more machines the lack of scalability soon bacame very apparent.
Luckily (for me) I’m more than happy to steal-and-adapt ideas that other people have already thought of.
bashrc.d/
The concept I’ve stolen is the /etc/*.d/
pattern. If you’ve seen one of these
directories you won’t be too shocked by the following explanation of my
setup.
The gist of my setup is to have a small snippet of code and a directory of useful (turn-offable) snippets.
The Small Code Snippet
I add the following to my .bashrc if it’s missing:
if [ -d $HOME/.bashrc.d ]; then
for x in $HOME/.bashrc.d/* ; do
test -f "$x" || continue
test -x "$x" || continue
. "$x"
done
fi
Snippet Directory
I make sure I have a directory: $HOME/.bashrc.d/
I fill it with small scripts that cover one or two features, and chmod +x
the scripts that I want to have ‘turned on’.
Here’s an example directory listing:
00.home-bin
bash-completion
common
git-aliases
git-color
git-persona
git-prompt
perl6
perlbrew
perlbrew-install
README.bashrc
Some examples
I’m sure you’re all happy with the directory listing and don’t need me to spoon-feed you bash setup commands but I’m still going to!
00.home-bin
This one has a strange name because it’s one of the few cases where order
matters; some later snippets call $HOME/bin
scripts.
#!bash
# add my own bin to my path
if [ -d ${HOME}/bin ]; then
PATH=${HOME}/bin:${PATH}
fi
perlbrew
In the same vein as home-bin, I also want to use my perlbrew - if I have it.
#!bash
if [ -f $HOME/perl5/perlbrew/etc/bashrc ]; then
source $HOME/perl5/perlbrew/etc/bashrc
fi
git-aliases
I don’t spend all of my time adding paths and environment settings, I also want to minimise the amount of times I type something like
git my-custom-thingy
and see:
git: 'my-custom-thingy' is not a git command. See 'git --help'.
so I have another snippet that runs and makes sure my git aliases are all injected correctly:
#!/usr/bin/env bash
if [ `which git` -a ! -f $HOME/.bashrcd.gitalias.lock ]; then
# we don't want to be running this multiple times concurrently
date > $HOME/.bashrcd.gitalias.lock;
# add aliases
git config --global alias.st status
git config --global alias.ci commit
git config --global alias.br branch
git config --global alias.co checkout
# etc
# and cleanup
rm $HOME/.bashrcd.gitalias.lock;
fi
How does it help?
It probably looks like there’s still a lot of manual copy-paste required to install this on a new machine.
This is where git comes in!
Once you’re happy enough with your set-up:
cd $HOME/.bashrc.d/
git init
git add .
git commit -m 'Initial commit'
then add the remote of your choice and git push
your hard work there.
Now a new machine setup is just:
git clone git://server/bashrcd $HOME/.bashrc.d
and adding the small code snippet to your .bashrc
I still have to manually copy something?!
No, of course not!
In your .bashrc.d/
folder create snippet.SOURCE.
Paste the snippet into it.
DO NOT make it executable!
Now you can do the following after your git clone
:
cat $HOME/.bashrd.d/snippet.SOURCE >> $HOME/.bashrc
source $HOME/.bashrc
Where’s the git repo?
I said I had a remote repo. I’m sure you’re wondering where it is.
It’s on github … unfortunately it’s a private repo because I haven’t separated out the $employer specific setup. Sorry!
I do a similar thing with my home directory. I have a .profile.d and a .bash.d, and I have my own lib/sh and bin directories, where I have some startup files. The .profile.d directory is for systems (like Ubuntu) that don't have sh symlinked to bash, and all of the file names are appended with .sh. The .bash.d directory has only .bash files, and that way I don't feel bad using any bashisms.
None necessary. It’s a weblog site for people involved with Perl, not a Perl article site. :-)
I've been thinking about ways to consolidate my various computer setups, and this is very helpful. Thanks!
Another related idea is to provide a way for a single .bashrc (and bashrc.d) to provide some custom settings amidst the same across every system. I like the idea of everything in a single directory, and maybe using (requiring?) a digit at the beginning of the snippet file name would provide the necessary utility.
Perhaps
0-*
host specific,
if [ "$snip_name" == "0-$(hostname)" ]; then source
[1-9]-*
run if executable
otherwise
warn it's not being run
Thanks for the post. I like this idea a lot. One nitpick, I think this is not necessary:
Shouldn't the test -x suffice?
I don't see how you could drop the '|| continue' and NOT execute/source the script.
As I see it you have a list of 'pass or escape loop' tests and finally you source the script if you get that far.
What would your suggested fix look like?
Some nice suggestions! I might think about incorporating them somehow.