Favorite Command Line Tools
Boost your productivity with these essential command-line tools
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).    Polling the Test Double brain trust EnablersWe’ll start with two tools that enable all the rest.HomebrewWebsite: https://brew.shInstallation: /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 iterm2Need a particular font for your favorite editor?brew tap homebrew/cask-fonts
brew search font
brew cask install font-firacode-nerd-fontHomebrew 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.tldrWebsite: https://tldr.sh/Installation: brew install tldrWhere was tldr back when I was in college?!? Pages were so detailed and in-depth that finding command-line help was a definite chore. Compare man tar versus its tldr tar counterpart:    man tar     tldr tar ✨ 🌈 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 stalwartsNext up are the everyday tools, the workhorses of a typical day writing code.ripgrep or The Silver SearcherWebsite: https://github.com/BurntSushi/ripgrepInstallation: brew install rgWebsite: https://github.com/ggreer/the_silver_searcherInstallation: brew install agripgrep 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 flagA 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 ghWebsite: https://github.com/github/hubInstallation: brew install hubWebsite: https://github.com/cli/cliInstallation: brew install github/gh/ghhub 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 checkouthub 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.ngrokWebsite: https://ngrok.comInstallation: brew cask install ngrokNot 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 clientsLet’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 1313Voilà! You now have your own URL, routed to an http service running on port 1313 on your machine.    Public URLs for local services is easy with ngrok 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-siteHat tip to Adam Lukens for pointing out this nice bit o’ functionality.pbcopy or xclipInstallation: Included with most *nix-based OSesThis 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 | pbcopyxclip’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.fzfWebsite: https://github.com/junegunn/fzfInstallation: brew install fzffzf 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/installRestart 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.    Better history searching with fzf Invoking fzf by itself triggers a file search, equivalent to doing find . -type f | fzf.    Better file searching with 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 pastingIn action:    Quickly and easily finding co-authors via fzf 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 lurkersThese are tools that usually end up aliased 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.exaWebsite: https://the.exa.website/Installation: brew install exaBilled 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:    ls     exa ✨ 🌈 batWebsite: https://github.com/sharkdp/batInstallation: brew install batJust 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:    cat     bat ✨ 🌈 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 logNeed to view an older version of a file in Git but still want syntax highlighting?git show v1.0.0:REAME.md | bat -l mdbat 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 | pbcopygrcWebsite: https://github.com/garabik/grcInstallation: brew install grcgrc 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    Watch grc add ✨ & 🌈 to every day commands! 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 expressionFor example:rails
rails.confWill 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_redThis 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:    Easy-to-spot errors in your log files, courtesy of grc grc makes the monotonous chore of scanning through long files a tad more colorful and a ton easier.Mighty handyThese 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 curlieWebsite: https://httpie.org/Installation: brew install httpieWebsite: https://curlie.io/Installation: brew install rs/tap/curlieHTTPie 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    curl     HTTPie ✨ 🌈     curlie ✨ 🌈 PUT of JSON data    curl     HTTPie ✨ 🌈     curlie ✨ 🌈 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.jqWebsite: https://stedolan.github.io/jq/Installation: brew install jqAt 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‍    Curling without jq 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 '.'    Using jq as a pretty printer Want the first book only?curl http://openlibrary.org/search.json?q=the+lord+of+the+rings | jq '.docs[0]'    A simple jq query 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}'    Stringing together multiple jq queries 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!tigWebsite: https://jonas.github.io/tig/Installation: brew install tigtig is a command line visual interface for git; where it really excels is in browsing a repo’s history.    Browsing a repo's history with tig     Viewing the details of a specific commit in tig One nice use/trick is to use tig to browse through and clean out your stash:tig stashlsofWebsite: https://people.freebsd.org/~abe/Installation: Included with most *nix-based OSesStop 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 :8080This 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.xargsInstallation: Included with most *nix-based OSesxargs 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 them uniq filters that list down to unique file names The list of unique file names is handed to xargs along with the command code, which invokes Wes’ editor of choiceThe 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 contentCongrats 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.”cowsayWebsite: https://github.com/tnalpgge/rank-amateur-cowsayInstallation: brew install cowsayWithout 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.