Bash your Workflow:
Getting your Environment Right
This post is part of Savvy Tips, a series of technical posts about how to improve your skills as a developer, written by our very own Alex Pearson, Head Instructor of the St. Louis cohort.
When you are a child you use a computer by looking at the pictures. When you grow up, you learn to read and write
As snarky as it sounds, I love the above quote (from William Shotts of linuxcommand.org). The change from interacting with your computer through click-able pictures and icons to using the text-based command line is a big one, but an important paradigm shift for anyone looking to use their computer as a tool. These “power users” using the command line aren’t just developers and programmers, but the category of people that has put in the time to make the transition to the terminal certainly includes aspiring Web Developers.
git, and use basic command-line programs. There’s a reason we cover these things in the very first day of class at Savvy Coders!
If you’ve already gotten through some of those basics, though, it might be time to start streamlining other parts of your workflow. Contrary to popular belief, programming is supposed to make your life easier, even if it’s intimidating at first. This extends to the command line, which supports a robust scripting language of its own. The real maestros of the development world can do some incredible things with these scripts (slight language warning on that link, but it’s a funny story that’s worth a read anyway). While these legends are a bit apocryphal, they speak to the power of the terminal and its associated scripting languages.
But where to get started? Maybe you’re not yet ready for one-button deploys of your million-dollar app or heavy-duty database management without a GUI, and that’s OK. The first step towards script-guru status is probably to start with the basics: the way your terminal looks, feels, and behaves, plus a few simple automations. Your environment, if you will.
Important Disclaimer: while the principles described in this post are applicable to a variety of different command-line environments, this post is specifically about using
bash (Bourne Again SHell), a particular kind of CLI. There are many different terminal emulators and applications out there on a variety of operating systems, from the Command Prompt and PowerShell on Windows, to
zsh on *nix systems (including Mac), to Mac’s default terminal emulator (which is a
bash prompt in login-mode). All of these tips should work with the default terminals for Mac or Linux variants, and will work with bash emulators of many kinds on Windows (see git-bash and, soon Bash on Ubuntu on Windows in Windows 10). For Windows users, don’t forget that there are also lots virtualization solutions for more, shall we say, powerful development with Linux (/end fanboy-ism).
The rest of this post will be focusing on using a
.bashrc file in your home directory to customize your
bash terminal. This file is automatically loaded by your
bash-flavored CLI (most of the time), and provides a lot of opportunity for customization of your command-line experience. You can tell a lot about a developer from their
.bashrc… their organizational skills (or mild OCD), their creative impulses, their day job, or even their favorite colors. You can see mine here. Feel free to copy it (or send me ideas on how to improve it!). It is, of course, a work in progress, like every
.bashrc should be. Much of this prompt was derived from this bash file from tldp.org, for those looking for a much more advanced
.bashrc file to play around with.
We’ll go over a three things in this post. These
.bashrc tips should apply to just about everyone that’s made it this far:
- Customizing your prompt.
aliasto create custom shortcuts.
bashscripts to run a simple operation (in this case, syncing my
.bashrcfile to GitHub)
Let’s get right to it!
Preliminary Work: if you have a terminal of some kind, you probably have a
.bashrc file in the root of your
$HOME directory. Try a quick
ls -a ~ command (which lists all of the files in your default home directory), and check for a
.bashrc file. If one already exists, you’re in luck! Open up that file with your favorite text editor, and let’s get started.
The Prompt: The default prompt for your terminal is probably some variation of the following:
This is, of course, colorless (boring!), and doesn’t tell you much of anything. We can assume that you already know your username, and you’re aware of which computer you’re using, so that info isn’t terribly helpful. It’s nice to see the
$, which tells us that the console is waiting for some sort of input, but that’s about it. As it turns out, we can add a lot more information to this prompt! As an example (representative only of my personal preferences, and by no means the Perfect Prompt), here’s the current version of my prompt as it appears on-screen:
Pretty sweet right? OK, probably not something to write home about, but I think this version of my
bash prompt) has a couple of nice features:
- Colors! And font-weights! These sound silly, but color is just another dimension of readability that can help you digest information. It’s the same reason we have syntax highlighters for code. In this case, the colors get brighter and bolder as the importance of the colored thing increases.
- A time stamp! Sometimes I like to be able to quickly see when I ran a command (“Has this command been running for 12 minutes already? Maybe something’s wrong”). But while the timestamp is nice, it’s not, as they say “mission-critical”. Hence the muted color scheme and inconspicuous position on the left-hand side.
gitintegration! Yep, that’s my current
gitbranch (and yes, I’m making edits directly to the
masterbranch because I like excitement and danger in my life) with an added color dimension: the branch name turns red when there are uncommitted changes, and green once everything in the current working directory has been committed.
- A real working directory! As you can tell by the obnoxious coloration, I think this is the most important part of the prompt. As Buckaroo Banzai said: “No matter where you go, there you are”. So, it’s nice to know where that is.
- A little arrow, which I happen to like better than the traditional dollar sign, but which isn’t terribly exciting. For those interested, I like
$because a lot of
bashinvolves variables, and
bashvariables usually include a dollar sign (see the aforementioned
$PS1or the soon-to-be mentioned
If you want to use this exact prompt, you’ll need to copy over the relevant color variables from lines 63-103 of my
.bashrc, followed by this thing:
This looks complicated (and it is), but we can walk through what’s going on here at a really high level:
exporting a new value for the default
- We’re using some of those saved ANSI escape codes to set the color of a 12-hour timestamp with
- A quick re-routing of the output from the
git branchcommand (which should be a list of available branches) to the null device (which is a way of saying “don’t show this output on the screen, but keep it in memory for processing later”) with
$( git branch &>/dev/null;
- Process the output from
git branchand check to make sure that it’s a “success” (code
0). If the current directory isn’t a git repository, then
git branchwill throw an error (which will not equal 0).
$?refers to the last command and
-eqchecks for equality. If this check fails, the
echos (or outputs) the colorized path (with
$Yellow$PathShort) followed by the red arrow (
- If the
if [ $? -eq 0 ]check passes, then a similar check is performed using the
git statuscommand. If everything is up to date, we expect output that includes the words “nothing to commit”. So a search is performed on the output of
grep, the output is sent into the ether of
/dev/null, and the success/failure of the
grepsearch is checked. If there’s something to commit, a red
gitprompt is shown with
echo "$IRed$(__git_ps1 (%s))";. The same is done in green if everything is up to date.
The specific syntax is, of course, a bit tricky, but also beyond the scope of this article. For now, copy and paste this prompt from the previously-linked gist, and see if you can change the variables/colors to your liking! If you’d like to customize your $PS1 further, there are also great starting points to be found in the many bash generators available online, as well as additional resources available for understanding the available special characters.
Aliases: There are some commands that you’re repeating all the time during the development process. Commands like
git add .,
git commit -m "some message" (you’re using these all the time, right? Right?!). They can be pretty tiresome to type all the time, so we can cut them down to size with the
alias keyword. Here are a few of mine:
Try out a few, and see how much easier your life gets (almost immediately). Especially great are those strings of commands that can be a pain to type out, but are often repeated (see
sudo service apache2 restart for working with Apache configurations or ). Those characters make a difference!
The first function saves a few characters, which is nice, and you can add in that commit message as an input through the
$1 variable. So
git commit -m "some message" becomes
commit "some message". Neat!
cherry-pit() is where things start to get interesting. This is my favorite little workaround for those times when you would like to selectively toss out a commit from a few minutes, hours, or days ago. It’s an entirely new
git function that takes a commit SHA and rebases it in such a way that it gets wiped out from the final commit history. Pretty cool! But these are just cracking the surface of what you can do with your own functions, reducing an entire string of commands into a single word input.
Task Automation: Hopefully you’re starting to see the power behind these bash functions, and how these tiny little quality of life improvements can help you really up your development game! To give you a hint at that future power, I’ll dissect one of the bash scripts I use all over the place in some form or another to push files to a “shared” location. This can be pushing files to GitHub, syncing development files between machines, or even deploying a website to a server (just like the server that’s serving up this blog post). Let’s take a look:
This one command will automatically save, stage, commit, and push a copy of my
.bashrc file to my GitHub account from any working directory. Not bad for a single
sbash! Let’s break down what this does piece by piece:
Here, a local variable is saved that equals the path to the folder that contains a copy of the
.bashrc file to push up as a gist later. Here I’m using the environment variable
$HOME, but could also have written this path as
~/Code/gists/env. In this case, using
$HOME lets me temporarily change the target of all of these operations.
This overwrites the contents of the
.bashrc file stored in the directory found at
$BashPath with the contents of my main
.bashrc file. This statement is then followed by (and connected by
&& to ensure completion of each task synchronously) this statement:
-C flag lets us specify a directory other than our working directory through which to perform the
add command. In this case, we’re restricting our
add command to the
This uses the same
-C flag to commit the changes with a commit message of “Update .bashrc”. If I wanted to change this to accept an input for different commit messages, I would just change the current message to
"$1" and execute
sbash with a commit message as the very next argument.
And, finally we push to the
master branch. Once again, we could specify a different remote and branch with
$3 if we were so inclined (but, for a single file like this, I am not so inclined).
All of that gets abstracted away behind a single
sbash, too. What a great win for future-you’s productivity!
What do you wish you could abstract away to make your life as a developer easier? What are those processes that you perform every day that ought to be done automatically? Maybe the solution can be found in your
.bashrc… give it a whirl, and post any questions, comments, or solutions to the comment section.
Good luck, and have fun
bash-ing your environment!