I love watching the masters at work. Trying to keep up as Rick Harding plows through code in vim, riding along as Sam Jones conducts multiple sessions in tmux, or marveling at Suz Hinton’s setup for live coding inspires me to up my own game and become a more productive developer.
With that in mind, a few weeks ago, I asked my fellow Test Double agents to share some of their favorite command-line tools (other than text editors).
Enablers
We’ll start with two tools that enable all the rest.
Homebrew
Website: https://brew.sh
Installation: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)
If you’re on macOS, then brew
is a great way to install and manage all the rest of the tools listed below:
# Search for a package
brew search hub
# Find out more info about a package, including good post-install steps
brew info postgresql
# Install a package
brew install rg
That’s just scratching the surface of what brew
can do. brew cask
can install GUI applications, extending brew’s package management into the .app
realm:
brew cask install firefox
brew cask install iterm2
Need a particular font for your favorite editor?
brew tap homebrew/cask-fonts
brew search font
brew cask install font-firacode-nerd-font
Homebrew supports bundling packages into a Brewfile
. I keep an updated Brewfile
with essentials for new laptop setup:
...
brew "git"
brew "vim"
brew "zsh"
...
cask "firefox"
cask "iterm2"
cask "bbedit"
cask "1password"
cask "fantastical"
...
Some tools, like Brooke Kuhlmann’s macOS or ThoughtBot’s Laptop, expand on the Brewfile
to create a rich system for quickly spinning up a new Mac. That said, a simple Brewfile
(with backups of course) is a great way to get up and running after disaster and/or a new hardware purchase.
tldr
Website: https://tldr.sh/
Installation: brew install tldr
Where was tldr
back when I was in college?!? P
ages were so detailed and in-depth that finding command-line help was a definite chore. Compare man tar
versus its tldr tar
counterpart:
I do not remember things like where I put my wallet, so I’m definitely not going to remember how to tar and gzip a directory. Consequently tldr
is an indispensable reminder of how to get stuff done.
Daily stalwarts
Next up are the everyday tools, the workhorses of a typical day writing code.
ripgrep or The Silver Searcher
Website: https://github.com/BurntSushi/ripgrep
Installation: brew install rg
Website: https://github.com/ggreer/the_silver_searcher
Installation: brew install ag
ripgrep and The Silver Searcher (rg
and ag
respectively on the command-line) were both written as faster replacements for ack
, but much, much faster. The Silver Searcher came along first, but ripgrep is slightly faster. Test Double agents are split pretty evenly with one vote also for git grep
.
Both tools let you specify a pattern to constrain searches. For example, if you want to find all the TODO comments in your JavaScript files:
rg 'TODO' -g '*.js'
ag 'TODO' -G '*.js'
These days I use rg
, having moved over from ag
; here’s why:
- Faster
- Ignores everything specified in
.gitignore
/.ignore
/.rcignore
files - Can search specific file types, e.g.,
rg 'TODO' -tjs
as another way to search JavaScript files - Full support for Unicode and colors; yes, you can
rg 👍
- Can search
gzip
,bzip2
, and other common zipped file formats with the-z
flag
A slight bump in speed, more power, and fewer bugs gives ripgrep the edge for me, but both tools are a big improvement over ack
or grep
.
hub and/or gh
Website: https://github.com/github/hub
Installation: brew install hub
Website: https://github.com/cli/cli
Installation: brew install github/gh/gh
hub
is the unofficial command-line tool for interacting with GitHub, while gh
is the still-in-beta eventual replacement. We’ll look at hub
first, as it’s still a more full-featured tool.
I use hub
for three main tasks:
hub sync
hub pull-request
hub pr checkout
hub browse
opens your current branch on GitHub in your default browser. I personally prefer viewing diffs in GitHub’s UI, so this is a nice shortcut to pop from the command line over to the browser.
hub sync
is like doing a git pull
for all of your local branches. It’s particularly handy when you want the latest on master
for a rebase but don’t want to have to mess around with checking out master, doing the git pull
, and then checking out your branch again.
hub pull-request
lets you create a pull request without having to leave the command line. hub pull-request -d
can be used to create draft pull requests.
hub pr checkout
lets you checkout a specific pull request. Let’s say you need to run a particular PR, #123, locally as part of reviewing and testing it. hub pr checkout 123
finds the associated remote branch and pulls it down locally.
Now let’s talk about gh
. One of the confusing parts of hub
is that it has two different subcommands for doing things with pull requests, as highlighted with the hub pull-request
and hub pr checkout
commands above. gh
fixes that, merging all pull request operations under one pr
subcommand:
gh pr create
is the equivalent of hub pull-request
.
gh pr checkout
is the equivalent of hub pr checkout
.
gh pr view
is the equivalent of hub browse
, with the extra ability of being able to open any pull request in the browser, not just the current branch.
Whoo-whee! That is one beautifully consistent interface!
As already mentioned, gh
is currently beta software, but by the time you read this post (hello, future you!) it may be ready to supplant (or having already supplanted) hub
, so it’s worth talking about both.
ngrok
Website: https://ngrok.com
Installation: brew cask install ngrok
Not every project will need ngrok
, but when you do, you’ll be using it on a daily basis. ngrok
’s website describes it as: “One command for an instant, secure URL to your localhost server through any NAT or firewall.” Why would this be useful? Let me count the ways:
- Enabling your remote coworkers to test or review your locally-running app
- Webhooks or 3rd party APIs that need to call back to a publicly accessible URL
- Demoing an app or web site to clients
Let’s say—and this is strictly hypothetical—that you’re writing a blog post. You want to go through one round of proofreading and edits before going to PR. Your local server is running on localhost:1313
but you’d like a publicly-accessible URL to hand to your proofreaders.
ngrok http 1313
Voilà! You now have your own URL, routed to an http service running on port 1313 on your machine.
Ngrok can also serve up arbitrary directories, so if you want to test some plain old static HTML but need it running on a server (behind basic auth):
ngrok http -auth="user:password" file:///Users/kyleadams/Code/static-site
Hat tip to Adam Lukens for pointing out this nice bit o’ functionality.
pbcopy or xclip
Installation: Included with most *nix-based OSes
This last set of tools is a bit different—they’re included with the *nix-based operating systems. pbcopy
and xclip
, on macOS and Linux respectively, let you pipe content into your clipboard. Building on one of our previous examples, here we pipe the results of looking for TODO comments into the clipboard, where it’s ready to be pasted into your todo list/productivity app of choice:
rg 'TODO' -tjs | pbcopy
xclip
’s syntax is a little more verbose than pbcopy
; fortunately Gary Woodfine has a nice set of aliases to bring pbcopy
ease-of-use to Linux systems.
fzf
Website: https://github.com/junegunn/fzf
Installation: brew install fzf
fzf
is a fuzzy finder. Developers may remember TextMate’s Cmd+T shortcut, which invoked a fuzzy finder for files in your project. Start typing any letters in the file’s path or name and it would jump to the top. In turn that feature inspired GitHub’s ’t’ shortcut to activate its file finder. ctrlp brought this fun to vim and now the latest incarnation is fzf
. fzf
, in addition to being a command line tool, also works in vim
.
Note: If you installed via brew
you’ll need to do a little extra work to finish fzf
’s command line installation:
/usr/local/opt/fzf/install
Restart your shell or source your config file and you’ll be good to go. fzf
’s installation integrates it into your shell experience; for example, using Ctrl+r to invoke a reverse search through your command history now has fuzzy finding powers.
Invoking fzf
by itself triggers a file search, equivalent to doing find . -type f | fzf
.
Where things really get interesting is when fzf
is used as part of a pipeline. Fellow agent Ross Brandes wanted to make it easier to attribute work done while pairing. He created, with assistance from Jason Karns, this alias:
alias coauth='printf "Co-authored-by: %s" "$(git log --pretty=format:"%an <%ae>" -1000 | sort | uniq | fzf)" | pbcopy'
Once the alias is setup, typing coauth
will:
- Find commit authors’ names and emails for the last 1000 commits in
git
’s log - Sort and filter out any duplicates
- Send the list to
fzf
for fuzzy finding magic - Append the selected name & email to the string “Co-authored-by: "
- Pipe that to the clipboard for easy pasting
In action:
If you want to dive into fzf
more (and you should), Alexey Samoshkin’s Vim universe. fzf - command line fuzzy finder is a good video to watch.
The lurkers
These are tools that usually end up alias
ed to a more plain-vanilla command, so that you often forget you’re benefitting from the extra pizzaz they bring to whatever command that might be.
exa
Website: https://the.exa.website/
Installation: brew install exa
Billed as a “modern replacement for ls
”. You could spend a lot of time in dotfiles hacking ls
to do some of the things that exa
does, but why bother? A simple alias in your shell’s startup file will suffice:
alias ls="exa"
Now all of your directory listings run faster, look better, and are Git-aware. You’re welcome. Feast your eyes on these amazing before and after screenshots:
bat
Website: https://github.com/sharkdp/bat
Installation: brew install bat
Just as exa
is a replacement for ls
, bat
is a replacement for cat
:
alias cat="bat"
bat
brings goodies like line numbers, syntax highlighting, git change markers, and automatic paging to the table. More beautiful before and after screenshots:
Furthermore, it can use those syntax-highlighting powers for awesome when tailing a log file:
tail -f /var/log/wifi.log | bat --paging=never -l log
Need to view an older version of a file in Git but still want syntax highlighting?
git show v1.0.0:REAME.md | bat -l md
bat
is also pbcopy
/xclip
aware, so if you pipe to either it will strip the line numbers and git modification markers out before sending file contents off to the clipboard:
bat TODO.md | pbcopy
grc
Website: https://github.com/garabik/grc
Installation: brew install grc
grc
is a slick tool for colorizing log output. It recently came to my attention thanks to a lightning talk given by Daniel Flynn on some of his favorite tools. As the docs for grc
say, “for the impatient - try [the] following commands:”
grc netstat
grc ping hostname
grc tail /var/log/syslog
grc ps aux
We can also set grc
up with custom configurations specific to whatever output format we need to make more readable. grc
uses ~/.grc/grc.conf
as its primary config file. Each entry in this file has two lines:
- a regular expression
- the configuration file to use for anything matching the preceding regular expression
For example:
rails
rails.conf
Will apply the configuration from rails.conf
to any rails command. If we peek in rails.conf
we find a different set of two lines:
regexp=\b\w+::\w+Error\b
colours=bold white on_red
This setup colorizes anything matching the regular expression; in this case, highlighting errors. Running grc rails server
and hitting a non-existent route colors the error as nice, bright, white-on-red text:
grc
makes the monotonous chore of scanning through long files a tad more colorful and a ton easier.
Mighty handy
These tools may not be used daily, but they’re incredibly useful when the need arises. Note that tldr
can be handy to remind you how to use these less frequent flyers.
httpie or curlie
Website: https://httpie.org/
Installation: brew install httpie
Website: https://curlie.io/
Installation: brew install rs/tap/curlie
HTTPie and curlie
are both replacements for the workhorse in a web developer’s command line toolbox, curl
. Much as with rg
vs ag
, which one you use is entirely up to you as both are significantly better than what they’re replacing. It’s important to note that, unlike the lurker tools, they are not drop-in replacements for curl
as they have a different interface. HTTPie is a new tool from the ground up, including the new interface, while curlie
is a wrapper around curl
to give it HTTPie’s easy-on-the-fingers user experience. Less talking, more showing, amiright?
GET
PUT of JSON data
I personally prefer HTTPie because I think its output is a little easier on the eyes, but I have no beef with others who prefer curlie
’s speed advantage.
jq
Website: https://stedolan.github.io/jq/
Installation: brew install jq
At its simplest, jq
is a pretty printer for JSON data. At its most powerful, jq
lets you slice, dice, and query JSON data from the command line. To demonstrate the power of jq
, let’s start with a simple curl
command (note that you can sub in http
or curlie
if you’ve alread installed either of those tools) that will search books via the Open Library API:
curl http://openlibrary.org/search.json?q=the+lord+of+the+rings
That’s quite a few books for a humble hobbit. Fortunately jq
lets you drill down into this data. If you just want JSON pretty printing and syntax highlighting, you can tell it to return the root node, i.e., everything:
curl http://openlibrary.org/search.json?q=the+lord+of+the+rings | jq '.'
Want the first book only?
curl http://openlibrary.org/search.json?q=the+lord+of+the+rings | jq '.docs[0]'
Better, but still too much information. What if we only want the title and author of the first book? jq
uses the |
operator to send the results of one query along to the next:
curl http://openlibrary.org/search.json?q=the+lord+of+the+rings | jq '.docs[0] | {title: .title, author: .author_name}'
Much better. jq
’s powers extend far beyond our simple example, so delve into the manual or this very nice tutorial if you wish, but remember: don’t dig too far or you may wake the drums in the deep!
tig
Website: https://jonas.github.io/tig/
Installation: brew install tig
tig
is a command line visual interface for git
; where it really excels is in browsing a repo’s history.
One nice use/trick is to use tig
to browse through and clean out your stash:
tig stash
lsof
Website: https://people.freebsd.org/~abe/
Installation: Included with most *nix-based OSes
Stop me if you’ve been here, done that: you start up your dev server, only to get a message that the port is already in use. You double check and confirm that you don’t have another instance running in a different open session. How do you find out which process is holding onto that port? lsof
stands for LiSt Open Files and provides a way to see which processes are opening which files. Since a port is handled as a file in *nix, we can use it to find which process is holding onto a particular port (8080
in this example):
lsof -i :8080
This is one of those tools that I only need every once in awhile, just long enough for me to forget how to use it… which is where tldr
comes in handy.
xargs
Installation: Included with most *nix-based OSes
xargs
is a *nix tool that takes input, splits that input up into a list, and then runs a provided command against every item in the list. It’s also one of those things that’s terribly abstract in explanation but so much cooler in practice. Fortunately developer Wes Bos provided a wonderful example of using xargs in a recent tweet:
🔥 Open all files that have a merge conflict in your editor
git diff –name-only | uniq | xargs code
Add an alias to your ~/.zshrc or ~/.gitconfig
xargs
is a unix thing, Windows users use WSL
alias fix="git diff --name-only | uniq | xargs code"
Let’s break that down a bit.
git diff --name-only
provides a list of names for files with difference in themuniq
filters that list down to unique file names- The list of unique file names is handed to
xargs
along with the commandcode
, which invokes Wes’ editor of choice
The end result is that each file with a merge conflict opens in the editor, ready for resolution. Note that you could easily swap code
out for vim
, emacs
, atom
, or whatever you prefer.
Bonus content
Congrats on making it this far (or cheating and jumping right to the end)!
If you’ve persevered, you deserve a treat, so our final tool is something its author describes as “simple and silly.”
cowsay
Website: https://github.com/tnalpgge/rank-amateur-cowsay
Installation: brew install cowsay
Without further ado, I present cowsay
(also courtesy of Daniel Flynn):
$ cowsay 'What do cows do for entertainment?'
____________________________________
< What do cows do for entertainment? >
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
$ cowsay 'Go to the MOOOO-vies!'
_______________________
< Go to the MOOOO-vies! >
-----------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
What next?
There are a lot of tools, maybe even an overwhelming amount, listed above. Choose one that seems most interesting to you and then incorporate it into your daily workflow. Master it. Once you’re comfortable, come back and choose a new one to learn.
My hope is that you leave this blog post feeling inspired by one or two of the examples above, ready to take the next step in boosting your productivity as a developer.