Five Tools That Will Make You More Productive on the Command Line
Last updated on by Paul Redmond
I’ve compiled a list of some of the CLI tools I think will make you a better, more productive developer on the command line. This isn’t an exhaustive list, but I’ve picked five CLI tools that I regard as some of my favorite productivity boosters when working with files and code on the command line.
Let’s start with one of my favorite tools on the command line: Fast Node Manager.
Fast Node Manager
You might ask: “But isn’t this post about using the command line better?” While Node.js version management isn’t necessarily helping you improve your command line game, it allows you to effectively navigate from project to project without having to think about which Node version a project is using and which Node.js version you use by default. You can also quickly install a new version of Node.js in seconds without leaving the command line.
You can choose between nvm, fnm, or a variety of other tools, but I like FNM just because it starts up faster when creating a new shell session. Admittedly, I haven’t used NVM in quite some time, so performance might have improved during shell startup. The main point is that both tools support .nvmrc
so it’s up to you as to which tool you want to install.
Bootstrapping to Your Shell
I am going to assume that you’ve installed your tool of choice. I assume that NVM and other tools have similar features, but I’ll use FNM in my examples to walk through the concepts of the setup.
The first thing I’ll call out is how I initialize FNM in my ~/.zshrc
file:
# ~/.zshrc file # fnmexport PATH="/Users/predmond/Library/Application Support/fnm:$PATH"eval "$(fnm env --use-on-cd)"
The --use-on-cd
flag is documented in the FNM README under setup, and what it does is run fnm use
when a directory contains a .nvmrc
or .node-version
file automatically. That way you don’t forget to run fnm use
when navigating between projects. I am not sure if other tools like NVM have this feature, but it’s really nice that FNM automatically takes care of switching for you.
The Setup
The first thing I like to do is pick a default Node version. When you open a new shell and the current directory doesn’t have a .nvmrc
file, FMN will default to this version of node. I maintain a dotfiles repo, and part of that repo installs a ~/.nvmrc
file in my home folder, so if I navigate to ~/
, FNM will run fnm use
and set that version.
You can still set a system default using the fnm default
command like so:
fnm default v21 # The above is a shortcut forfnm alias default v21
After running the above command, you can check which versions you have installed, the current selected version, and the default:
$ fnm list* v14.21.3 lts-fermium* v16.20.2 lts-gallium* v18.19.0* v20.10.0* v21.5.0 default, v21* system
Note the system
option, which bypasses FNM and uses the installed system version of node. This is nice because you can eject out of FNM or even make the system installed Node your default.
FNM makes it convenient to install new versions, which you can do using the install
command:
fnm install v12
If you don’t recall which version or want to see a list of all the possible versions you can install, use the list-remote
command:
$ fnm list-remote # or aliases$ fnm ls # alias for list$ fnm ls-remote # alias for list-remote
Though it seems like a requirement, I still think tools like FNM make it a cinch to stop worrying about installing various node versions you’ll need as you develop multiple projects. Even if you want to see about upgrading, you can easily adjust the .nvmrc
file in your project to work on upgrading your app.
Auto Suggestions
The first time I learned about command line auto suggestions for ZSH, I heard them called “Fish-like autosuggestions for ZSH.”
These auto-suggestions are really nice to quickly repeat commands that are hinted as you type and I’ll show you how to complete them without leaving your keyboard home row! Before we look at that, let’s see how I set mine up.
The Setup
Most shells have this feature nowadays, and my shell of choice is Z shell. The package I use is zsh-autosuggestions, which you can install in a variety of ways.
I use Oh My Zsh, and setup is as easy as cloning the repo into your plugins folder and enabling the plugin:
$ git clone https://github.com/zsh-users/zsh-autosuggestions \ ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
Then I enable it in my plugins()
within the ~/.zshrc
file:
plugins=( # other plugins... zsh-autosuggestions)
After running omz reload
or opening a new terminal session, I get some shiny auto-suggestions:
Using Autosuggestions
Command line autosuggestions are straightforward in that they suggest the most relevant thing based on what you’ve typed. If I type php
it will suggest the rest if it’s a command that I’ve run before. At that point, I can use the arrow keys to navigate through all the commands that start with php
.
The most important shortcut for me when using autosuggestions is completing the command. You can do so by reaching over to the right arrow key, or you can run hit ctrl + f
to finish the suggestion:
You can also go forward-word
to jump to the next word in the suggestion, which for me in iTerm 2 is ctrl + ] f
. Check out the zsh-autosuggestions repo for other customization options and tips.
Zoxide: A Smarter CD Command
I enjoy using ZSH’s cdpath()
to configure common directories that I navigate. For example, I might have a path for all my personal GitHub repos in my cdpath()
like so:
cdpath=(~/code/github/paulredmond)
That allows me to quickly navigate to projects in that path using tab completion:
# from anywhere$ cd my-secret-project # ~/code/github/paulredmond/my-secret-project
Another tool I enjoy using for faster navigation on the command line is zoxide. It remembers which directories you use frequently, so you can jump to them with a few keystrokes. It is called a “smarter cd command” in the readme, which I think you’ll enjoy:
Setup
The nice thing about zoxide is that it has multiple ways to install the package for every OS. I am on macOS and dabble with Rust, so I used cargo to install. It has Homebrew and MacPorts (I guess that’s still a thing) options as well as various others.
Since I am on macOS, I just add the following to my ~/.zshrc
file to initialize zoxide (which also aliases z
):
# zoxideeval "$(zoxide init zsh)"
Once refresh my terminal session, zoxide is ready to start learning our navigation habits.
Training Zoxide
There are a few ways we can start helping zoxide learn. Personally, I didn’t want to alias cd
at first, so I used the z
command which zoxide aliases. At this stage, you can teach zoxide about your most frequently visited directories:
z ~/code/github/paulredmond/secret-projectz ~/code/work/z ~/.ssh/# ...
Now I can type just a few characters and zoxide will fuzzy find my secret project:
$ z sec
What’s really nice (once we get fzf set up) is that you can quickly find groups of folders, for example laravel-
packages:
z laravel
One last note: if you have multiple paths with the same name you can pass multiple arguments to zoxide:
z se logs# which might navigate to secret-project/storage/logs
Zoxide is an excellent package on its own, but it also shines in combination with fzf
.
fzf: A Command Line Fuzzy Finder
The fzf package is a general purpose command line fuzzy finder that filters through results fed from other tools such as zoxide
or vim
. You can use fzf in a myriad of ways; however, I suggest familiarizing yourself with the setup basics and a few zsh plugins I recommend:
The Setup
Following the installation section of the project’s readme, you can install fzf
via Homebrew on macOs, various packages for Linux, and pre-built binaries are also available for Windows.
After installing fzf
, I recommend running the install
script. Depending on your OS, the path will vary. I used Homebrew to install fzf
so for me this install added everything I wanted:
$(brew --prefix)/opt/fzf/install # Or just say yes to everythingyes | $(brew --prefix)/opt/fzf/install
After you finish the installation, you’ll need to reload your shell to pick up the files added to your shell configuration file. You can verify that fzf
is available with which fzf
and you
fzf Basics
The first thing you can try with fzf
is running ctrl + r
to fuzzy find history (if you picked y
to install key bindings). Fuzzy finding gets really powerful one you learn the search syntax, but out of the box without any knowledge it’s much better that tabbing through folders:
One immediate cool feature I found useful is using **
to hit tab in the middle of a command instead of canceling out a command if you don’t know the exact name:
subl app/**
As I am typing the above command, I can hit tab, which will open the fuzzy finder and allow me to complete the command without having to back out and do something like ls
to find the file path:
Let’s say you’re on a server or your local machine and need to find and kill a process—using fzf
makes it a breeze. Instead of using pgrep
first and then kill -9
you can just run kill -9 **
and fuzzy find the process you want to kill:
The applications of using fzf
is seemingly endless, so I encourage you to see where this plugin can help you. We didn’t cover fzf vim, but if you’re a vim user, you probably already know about it 😆
fzf-tab
The fzf-tab plugin replaces zsh's default completion selection menu with fzf. You can install this in various ways; I specifically installed fzf-tab as a plugin for Oh My ZSH, but the only requirement to use fzf-tab is that you’re using z Shell.
Using fzf-tab at first was jarring for me because it hijacks anywhere you’d use tab completion in your shell and replaces it with fzf. However, where it shines is navigating around the filesystem or checking out a branch with git
from the CLI:
As I mentioned, when I first started using fzf-tab
the experience was jarring, so if you want to try it out, you can always eject from using fzf-tab during the middle of a terminal session with the disable command:
# Disable fzf-tab$ fzf-tab-disable # Reenable fzf-tab$ fzf-tab-enable # Or just remember one command for both$ toggle-fzf-tab
zsh-artisan and fzf-tab
The last thing I want to show you with fzf-tab
is using it in combination with the zsh-artisan plugin, which lets you fuzzy find an Artisan command without having to scan the available list if you forget an exact command name:
RipGrep For Blazing Fast File Searches
I have a dedicated post that covers Command Line Search Tools for Programmers, but RipGrep gets a mention here because, in my experience, it’s the absolute fastest and is my primary search tool on the command line.
Ripgrep automatically respects .gitignore rules, skips binary files, and skips hidden directories by default. RipGrep has many features, so the best way to get familiar with it is to read the man rg
page.
Here’s a quick preview of how you might use it to search PHP files for a specific string:
$ rg --type=php Controllerapp/Http/Controllers/Controller.php 3:namespace App\Http\Controllers; 5:abstract class Controller
Learn More
I hope you’ve found helpful CLI tools to add to your repertoire. I've tried to share a variety of complimentary tools that you can use in tandem, but feel free to take it slow so you don't have too many new things at once! Let us know on your favorite social media tool what your favorite CLI tools are!