Command Line Fu

Alright, maybe the title is a little pretentious, but hopefully this isn’t a total disappointment.

So if you have been on a linux or mac system as your main workstation for any amount of time, or have recently moved to it, or even just considering adopting it now, you have had to spend some time in the terminal. Even little hacks that improve your terminal workflow can be a massive productivity boost, and this is what we are going to talk about today.

This is obviously a VERY opinionated post, its really just a catalog of some software/tips/tricks/commands I have picked up over the years, YMMV.

First a quick list of all the main things we are going to talk about today:

  1. Default shell – zsh
  2. Shell Configuration Framework – Prezto
  3. Fuzzy Finder – FZF
  4. Quick Access to Files and Directories –Fasd
  5. Shell Extension – direnv

There is lots more, but this is a pretty good list to get started with. Now if you are a Homebrew user on a mac (or linux), you can install most of that with a single command:

brew install zsh nvim fzf iterm2 tmux direnv fasd

and then simply clone the prezto repo from the link above. Now each one of those projects is pretty awesome and powerful, so I highly recommend reading their documentation, quick shout out to all the amazing open source folks out there who let us have stuff like this for free!! Please try to find an author or two you really like and support them on Patreon. Some of my favorite open source authors/projects are:

There are tons of other folks, doing amazing work in the open source universe, lets show them our gratitude.

Alright back to our post, please note, there is really (equally?) good alternatives to pretty much all of these tools, but this post isn’t meant to do a compare/contrast (maybe we will someday), today we are simply going to look at some basic features these tools offer and how we can use them to improve our daily workflow.

Default Shell and Configuration

There is lots of reasons why you would want to consider switching your default terminal to ZSH, but I like it mostly for the plugin/theme support. I have gone back and forth between Oh My ZSH and Zprezto, Zprezto seems to (anecdotally) perform better for me.

Some examples of things ZSH + Zprezto do for you out of the box are:

There is plenty more where that came from, to make full use of the power of ZSH and Zprezto please refer to their documentation. The community managed Reference Card is also pretty handy.

Fuzzy Finder

FZF is a magic tool, that adds fuzzy finding capabilities to any list on your terminal!!!

Let’s say you want to find a file, but don’t remember its full name (or are too lazy to type it) or maybe you can never remember all the flags for the find command or just not in the mood for a complex grep pipeline. Well, FZF to the rescue!! If you installed FZF using the brew command above, simply run $(brew --prefix)/opt/fzf/install to install all the goodies. Once you do that, run fzf on the command line and start typing some combination of letters in the filename your are searching for. Isn’t this so much better than find . -type f | grep -E <some regex>??

Only looking for files that end in .py? Type fzf and then .py$, where $ indicates end of line.

FZF by default only prints the file name, but lets say you want to do something more useful, like opening the file up in vim:

vim -o `fzf`

This will let you fuzzy find the file and then open it in vim directly!

Can’t remember some command you ran a while back to convert a certificate from pem to crt? Try adding this as in your ~/.zshrc

h() {
  print -z $( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s --tac --height "50%" | sed -E 's/ *[0-9]*\*? *//' | sed -E 's/\\/\\\\/g')
}

Now reload your shell with say: exec $SHELL -l, and run h, yes CTRL+r is so 2013 you can now fuzzy search through your command history, see it in action below if you don’t believe me:

There is a lot more you can do with fzf, see this article from Techmint.com for some good tips.

Navigating Directories

If you are like me you have tons of personal and professional projects all stored in a neat (& deeply) nested folder structure, but switching projects means remembering where each file/folder is, and sometimes typing out deeply nested directory locations. This is where fasd comes to our rescue, fasd comes with some defaults built in already for common tasks like navigating to a directory or open a file in vim. So instead of typing

cd /Users/faraaz/developer/samtek/blog/blog/content/post/

I can simply do:

j post

Or to open the file for this post in vim, I can do:

v command line

instead of:

vim ~/developer/samtek/blog/blog/content/post/command-line-fu.md

Maybe you don’t remember anything about the directory structure and want to interactively select the directory from a list of your most recently visited ones, try:

zz

Lets see this in action:

Neat, isn’t it!

Managing configuration

Now that we have learned how to improve the speed of common day to day activities on the terminal, lets take a look at another common problem. Most of us have project specific configuration. While some people might debate whether or not environment variables are the right place to store configuration, it has been recommended as a best practice for a while now (See: 12 Factor App) and let’s face it, its pretty handy.

Besides if you work in the cloud, you probably have access to a few different cloud provider accounts. Access to these profiles can be managed by setting environment variables like AWS_PROFILE or AZURE_DEFAULTS_GROUP.

Alright, great! But how do I change these environment variables everytime I switch into a new project (directory), you ask? Direnv was built precisely for this reason. It has a very simple API, all you need (after you install/enable it) is a .envrc file in your project directory. Once you have allowed this file to load by running direnv allow inside your project directory, direnv automatically handles the loading and unloading of environment variables as you cd in and out of project directories. So lets say you have two projects, one personal and one work related. Each of these projects uses a specific AWS account, named, personal and work, and you have top level directories for these project, named, once again, personal and work. All you need to do is set up your aws cli/sdk/tool with named profiles and have the following .envrc in your project directories.

cat ~/personal/.envrc
AWS_PROFILE=personal
cat ~/work/.envrc
AWS_PROFILE=work

Now as you cd in and out of these directories, you will see direnv is doing its magic:

cd ~/personal
direnv: loading ~/personal/.envrc

env | grep -i aws_profile
AWS_PROFILE=personal

cd ..
direnv: unloading

Once again, this isn’t meant to be a full on tutorial on direnv, just enough to peak your interest. If you would like to learn more about what direnv can do, please see their documentation

There is so much more to talk about on command line productivity (tmux anyone?) but I just wanted to introduce some really essential tools to my workflow on a day to day basis, I am sure a lot of you have tips/tricks/tools you love as well, please do tell me about them. You can tweet me at @mfyk84 or hit me up on linkedin

command-line-fu