How to Customize Your Bash Aliases Based on the Current Directory
I love the keyboard, and I hate the mouse. Seriously. If I can go 2–3 hours without touching my mouse, that’s a huge win. Mousing is just so inefficient, especially when it comes to development work.
As you can imagine, I’m also a huge fan of the terminal. I delight in showing new engineers on my team how to get the most out of their terminal. We even have a whole doc in our team drive titled “Terminal Swag” with tips, tricks, and best practices for working on the terminal.
Of course, terminal commands can be a bit tedious to type. That’s where bash aliases come in. I have a prolific bash alias file. It’s second nature to open a terminal, cd to a project folder, and type startup
before beginning work. Starting watch mode just means typing watch
, and running a dev build is just build
. Ready to start a PR? No need to open chrome or navigate to GitHub manually — just type create_pr
in the terminal, and chrome opens to the “Open a Pull Request” page with my current branch selected.
Right around the start of the pandemic, I decided it was time to ditch the dual-boot and switch to Windows Subsystem for Linux (WSL). I got all of my work repos, scripts, and aliases transferred over, but since I wasn’t doing much personal project work I never quite got around to setting up the personal side of things.
When I decided to start some new personal projects this week, I quickly realized that I was going to have problems. My startup
, build
, and watch
aliases (among others) needed to be different for different projects. I tried startup_projA
, watch_projB
, etc. These were just annoying and hard to remember. My hands want to type build
, not build_newProj
, darn it!
After about 20 minutes of googling determined that there wasn’t an existing solution that quite met my needs, I decided to write my own utility. (The ability to write software to do a thing is quite possibly my favorite part of being a software engineer.)
My requirements were pretty simple:
- I should be able to define aliases in any directory.
- When using the terminal, I should have access to the aliases defined in the current directory and those defined anywhere above the current directory.
- Aliases that are defined lower in the tree (i.e. in a more-specific folder) should override aliases with the same name that are defined higher in the tree.
- Aliases defined in my home directory should always be included, even outside that directory.
- Aliases should automatically update themselves whenever I change directories in the terminal.
My main languages are JavaScript and PHP. I’ve dabbled in Python, C++, C#, Java, and Ruby. Even so, I knew the right language for this project was Bash. All languages have their quirks, and even though I hadn’t done much Bash scripting before, I figured it wouldn’t be that difficult.
Y’all, Bash is weird. Non-function blocks don’t get braces — instead, they’re terminated by writing the command backward. That’s right, to end an if
block, you type fi
, and case
statements end with esac
. I can’t make this up.
Functions DO get curly braces, but no parentheses (or if they do get parentheses, they’re just for show), and your return value can only be an integer between 0 and 255. Oh, and true booleans don’t exist, but 0 is truthy, while any non-zero integer 1–255 is falsy. Weird.
I spent the next few hours googling syntax, reading arcane documentation, and trying to figure out why some conditional expressions need single brackets, some need double brackets, and some need no brackets at all (!). The end result is a utility I’m calling aliasme — which I’ve open-sourced so nobody else has to do this (unless you really want to, in which case you do you).
aliasme works by starting from the current working directory and walking up the directory tree looking for .bash_alias
files. It then includes them in .bashrc
/ .bash_profile
in order from least-specific (e.g. ~/.bash_aliases
) to most-specific ( ~/personal/repoA/.bash_aliases
).
It also includes a script that attaches itself to $PROMPT_COMMAND
, which fires just before a prompt is displayed. If the script detects a directory change since the last time the aliases were calculated, it triggers a recalculation. This ensures that I always have my work startup
command when I’m in my ~/work
directory or any of its children, but when I switch to my ~/personal
directory, startup
is defined within each individual repo.
And that’s it! I hope this article (and the aliasme script) is helpful to someone!
Has the pandemic created any interesting problems that you’ve solved with code? I’d love to hear about them!