Last Updated: February 25, 2016
· philm

Directory specific bash aliases

When using Docker for development, especially Docker Compose, commands that used to be short and sweet in pre-Docker days end up lengthier in order to route commands through a running container, e.g.

docker-compose run web rails g controller users 

While there are some obvious solutions, such as defining aliases in your shell config, e.g.

alias web="docker-compose run web"

these require you to adopt global conventions that might not always apply if you are collaborating on multiple projects.

While the following shell hack can certainly be used in any context, I use it primarily to scope commands to specific directory trees on my dev box. This way, when I leave the tree, everything gets cleaned up, avoiding global bloat.

First, add the following functions to your bash config - either directly to ~/.bashrc or in a separate file that is then sourced by your .bashrc:

function on_leave_dir() {
  if [ -e .aliases ]; then
    export OLD_ALIAS_DIR="$PWD"

function on_enter_dir() {
  if [ -n "$OLD_ALIAS_DIR" ] && ! is_subdirectory "$PWD" "$OLD_ALIAS_DIR" ; then

    while IFS=':' read -r key value || [ -n "$key" ]; do
      unalias "$key" > /dev/null 2>&1
    done < $aliases

    unset OLD_ALIAS_DIR
    echo "Unloaded local aliases"

  if [ -e .aliases ]; then
    while IFS=':' read -r key value || [ -n "$key" ]; do
      alias "$key"="${value##*( )}"
    done < ".aliases"

    echo "Loaded local aliases"

function is_subdirectory() {
  local child="$1"
  local parent="$2"
  if [[ "${child##${parent}}" != "$child" ]]; then
    return 0
    return 1

function cd() {
  builtin cd "$@"

Next, in any directory you'd like to trigger one or more aliases, added an .aliases file, using a simple key value format:

logs: docker-compose logs web
rails: docker-compose run --rm web rails

Now, any time you enter that directory, you can run the (short and sweet) commands:

rails g controller users 

While the above command looks and feels like a normal rails executable, it is actually an alias that is routing the command to the rails executable running inside my Docker container.

You can also re-define the aliases in other directories using the same key names without any conflicts.