As I am an avid *nix (mostly Ubuntu and OSX) user, I’m constantly trying to improve my workflow in the terminal (I use the Bash shell) and my dotfiles. One recent development has been the use of directory specific environments. Before getting into that, let’s talk about what happens when your terminal fires up.
Loading the Environment
When you fire up xterm or the Terminal.app, Bash looks for one of two files:
.bash_profile. On most unix-like systems, including Ubuntu, xterm opens in a “non-login shell”, and non-login shells
source (more on this later)
.bashrc. Login shells – any shell where you have to type your username and/or password – will load the
Bash will look for both
.bash_profile in your
$HOME directory. You can find out what that is like this:
shell$ cd ~
On most linux distros it’s something like
/home/[your_user_name]; in OSX it’s
Use the Source
Above, the word
source was thrown around. This just means read and execute the file. It’s roughly the same as Python’s
import or PHP’s
include. Any code statements in the main body of the file (eg. not inside a function definition) will be executed.
The essential idea of sourcing the
.bashrc file is to set up your environment. You can change whatever you want here – like defining a custom prompt or setting up aliases.
Unfortunately, the same “environment” might not be needed everywhere. Here’s a few examples:
- The EC2 command line tools requires several environment variables. If you manage multiple clients on EC2, they’ll need separate certificate files active in the environment. You’d have to set those up every time you needed to use the EC2 tools.
- Using Python’s virtualenv effectively replaces your current set up with one that uses a specific set of libraries
If you need to set up different environments, the solution is simple: create a file name
.env and put all the things you need to run in it. Source the
.env file after entering the directory to set up a directory specific environment.
shell$ cd /path/to/a/dir
shell$ source .env
Piece of cake! But that’s not very fun. Let’s see if we can make it happen automagically when we cd in.
Here’s a little function that checks to see if the file exists then sources it.
if [ -f "$PWD/.env" ]; then
Now, let’s make that function run every time we cd into a directory. We’ll create another function that tries to run the build in
cd and, if successful, run the
maybe_env function to source the
if builtin cd "$@"; then
Now we just need to alias
cd to run
Every time you entire a directory, bash will look for the .env file and and source it if it’s there!
Problems & Improvements
The above works, but it will source the .env file every time you enter the directory. Not a big deal, but not efficient. It should only load the
.env if it hasn’t already been loaded. As a way around that, let’s improve the
maybe_env function to…
- Check if
- Check to see if the
CURRENT_ENVenvironment variable is set or if it’s pointed to another
.envfile and source the current
.envfile if necessary
if [ -f "$env" ]; then
if [ -z "$CURRENT_ENV" ]; then
# no current environment, source .env file
builtin source "$env"
elif [ ! "$CURRENT_ENV" = "$env" ]; then
# we have a current environment setup
# the environ we have setup is not this one
# check to see if we have a deactivate function to run
if [ "$(type -t deactivate)" = "function" ]; then
builtin source "$env"
The above will store which
.env file is in use and only try to source if
CURRENT_ENV isn’t set or is pointed elsewhere. It also attempts to deactivate the old
There are all sorts of cool things you can when CD’ing into a directory. Like setting up directory specific history or running
git status. Settings up a little directory specific environment is just one example.