Have you noticed that, as an engineer, in every tech organization/team/project there are activities you repeat on a daily basis, often multiple times per day?
These activities might look like:
- Switching between different installed versions of
nodeorjava - Running a long build command like
mvn clean install -DredirectTestOutputToFile - Listing S3 buckets on
dev/stage/prodAWS accounts - Populating local database with test data from Staging environment
- Running multiple commands chained with
&&from the terminal
These are often very specific to the organization/team, due to the nature of the work the team is doing and the organizational processes that guide the work.
Although a necessary part of everyday work, these activities can drain significant amounts of our daily energy, especially if they take a long time or are repeated multiple times per day.
Sometimes doing a “quick check” is preceded by an established, but nevertheless time-consuming, process of running a database query that we need to recall from memory or find and copy from our notes.
How many times do we find ourselves searching Slack/Teams history for a build command that someone sent us, which requires switching from wherever we were at the time to Slack, searching, sifting through answers, copying it and coming back to run it?
Those working with AWS from the terminal know all too well that however powerful aws cli might be, it comes with a verbosity tax. It allows us to perform almost every action on AWS from the terminal instead of navigating the UI, which is fantastic, but we also need to type out commands like this to e.g. switch between environments:
eval $(aws configure export-credentials --profile dev --format env) # for development environment
eval $(aws configure export-credentials --profile stage --format env) # for staging environment
eval $(aws configure export-credentials --profile prod --format env) # for production environment
For anyone working in a microservice codebase, chances are the git checkout main will fail in some repositories because the branch is called master or vice versa. However, it will work as expected in another repository, depending on when it was created and what convention was followed at the time.
This is exactly where shell can make things easier for us. Terminal shell (like bash, sh, zsh) supports aliases and functions .
An alias allows us to give a short name to a single-line command:
alias dev='eval $(aws configure export-credentials --profile dev --format env)'
and then invoke it in terminal by its new, short name:
dev
# command 'eval $(aws configure export-credentials --profile dev --format env)' runs
Alias can be as short as one character, which is handy for commands that we run frequently, such as a project build command.
alias m='mvn clean install -DredirectTestOutputToFile'
m # command runs
Aliases are limited to a single line, and sometimes we want to run multiple commands as a single “step”.
Suppose we are testing out the latest release which is packaged as a .tar.gz archive, and we need to download it, extract it, and run a script inside it. In this case, we can write multiple commands as a function:
check() {
wget -O latest.tar.gz https://example.com/latest.tar.gz
tar -xzf latest.tar.gz
./latest/run.sh
}
and call it in the terminal with
check
# all of the commands run
Defining aliases and functions in the terminal will make them available only for that terminal session. To make them available permanently, we can add them to a /home/user/.bashrc (where user is your username on Linux), so they survive a terminal restart.
.bashrc is a script that is automatically read (“sourced”) when an interactive terminal starts, and all the functions and aliases in it become available to you.
Depending on the OS/shell, the name and path of this file can differ, but the intention is the same. For zsh on macOS it will be /Users/user/.zshrc.
Additionally, because the .bashrc is sourced at the start of the session, there is autocomplete for aliases and function names!
You might be thinking “That’s all fine, but I don’t even know enough shell scripting to write those commands in the first place”. There’s good news:
- Most of the time, the functions would be thin wrappers around the commands you are already running manually
- LLMs can help write those for you and the gaps you might need to fill shouldn’t be too complicated, even if you’re not familiar with shell scripting
- Due to their nature, these functions/aliases are written once and run often multiple times per day, so it pays off to put some effort up front, and it will continue paying dividends down the road
Chances are that whenever you need to do some task for which you already have an automation in the form of a shell alias/function, you will feel the joy when typing out a simple command. Not having to remember some flow for a particular task and saving yourself a fair amount of focus and daily energy for the day is a gift that keeps on giving.