DEV Community

Cover image for 6 Command Line Tools for Productive Programmers
Adam Gordon Bell
Adam Gordon Bell

Posted on • Updated on • Originally published at earthly.dev

6 Command Line Tools for Productive Programmers

Lately, I've been doing a lot more things at the command line. I'm not a hard-core terminal guy -- I use VSCode more than Vim -- but I'm always surprised at the number of complex tasks that can be done using just the POSIX standard command-line tools like grep,cat and sort.

Tools are powerful. A good tool makes work easier and faster, and a great tool unlocks new abilities: Previously impossible things become possible and sometimes easy.

As I've learned more I've been adding some new tools to my command-line toolbox, and in this article I'd like to share some I've found valuable.

broot

I'm not sure how I came across broot, but it's pretty handy. If you are in a small directory and want to see the lay of the land, tree is excellent.

✗ tree
.
├── dartboard.png
├── header.jpg
├── opensign.png
├── quote1.png
└── trophy.png

0 directories, 5 files
Enter fullscreen mode Exit fullscreen mode

However, if the directory has many files or sub-directories, tree becomes much less helpful: you only see the last screen full of information as files scroll past you.

$ tree 
< scrolling text for a long time >
├── banner.js
└── index.html

328 directories, 2028 files
Enter fullscreen mode Exit fullscreen mode

broot solves this problem by being aware of the size of your terminal window and sizing to fit it.

broot

You can navigate around using the arrow keys in broot and it is also helpful for tracking down disk space usage by passing in the -w flag (broot -w):

Broot2

It can do lots of other things, so take a look at the GitHub guide but for me its just a better tree.

ℹ️ Install BRoot

Install on MacOS using brew or follow installation instructions for other environments.

brew install broot
Enter fullscreen mode Exit fullscreen mode

Funky

If you live in the terminal, and you want to use your terminal as an IDE, then it's helpful to have your terminal change based on the current directory. There are many ways to do this. DirEnv loads and unloads .env files as you enter directories. smartcd is similar. It lets you run a shell script whenever you change to a certain path -- you can start and stop services, change the prompt, or anything else you want.

However, my favorite of this genre is the strangely named funky, which "takes shell functions to the next level by making them easier to define, more flexible, and more interactive."

The way funky works is simple: as you enter a directory, funky looks for a .funky file which contains a list of bash functions. It loads them, and when you leave, it unloads them.

This means when I'm in the directory for this Jekyll blog, I have aliases loaded for creating a new post, linting my markdown, pulling in images, and so on. I can list these by typing funky

$ funky
lint() { markdownlint --fix "./_posts/*.md"; }
set-header() { cp "$(latest-image)" "$(image-folder)/header.jpg"; }
set-image() { cp "$(latest-image)" "$(image-folder)/$(date +%s).png"; }
Enter fullscreen mode Exit fullscreen mode

funky can do more than this, though. It has features for interactively adding and editing functions, and for registering global functions and aliases. What I like, though, is just being able to quickly give a command, in a specific context, a short alias.

ℹ️ Install Funky

Install Funky using pip

pip3 install pyfunky
Enter fullscreen mode Exit fullscreen mode

Then add hooks to your .zshrc, bashrc or equivalent:

## find where funky.sh was installed by pip and source it
source /usr/local/lib/python3.9/site-packages/scripts/shell/funky.sh
Enter fullscreen mode Exit fullscreen mode

Fuzzy Finder (FZF)

FZF

If funky and broot improved my productivity then more tools could only improve it more, right? So I headed over to Lobste.rs and asked what other tools people were using. FZF came up quite a bit, and I've started using it myself now.

FZF is a command-line fuzzy finder. It's fast, and it interactively lets you filter options down based on a fuzzy keyword match in many places where you need to input a value at the command-line.

If you install the included shortcuts (/usr/local/opt/fzf/install), you can use ** anywhere and get an interactive fuzzy finder to narrow down to the desired path. FZF also makes searching your history much faster.

It's a unix filter that reads in input, shows you an interactive list that you filter down and then sends the selected item out the other side but describing that way undersells its usefulness.

I recommend watching this video where Alexey Samoshkin walks through many possible uses for FZF with a soothing piano playing in the background.

ℹ️ Install FZF

Install Funky using your package manager of choice:

brew install fzf
Enter fullscreen mode Exit fullscreen mode

Then add hooks to your .zshrc, bashrc or equivalent:

#ZSH
source ~/.fzf.zsh 
#BASH
source ~/.fzf.bash
Enter fullscreen mode Exit fullscreen mode

McFly

MCFly

FZF is excellent for filtering file paths in a command line when you want to open a file (vim **), but for command-line completion, there is more information available than the raw history file. McFly attempts to use this extra information to provide more relevant results.

What extra information? To start with, McFly considers these options in its ranking heuristics:

  • The commands you typed before the command.
  • How often you run the command.
  • How recently you ran the command.

It tracks all this in a SQLite database where it also tracks and weighs suggestions by:

  • The commands exit status.
  • The directory you ran the command in.
  • If you have selected it in McFly before.

Being suggested failed commands is a pet peeve of mine, but I never considered narrowing the choice based on the current directory or down-ranking items that are never selected.

McFly uses a neural net to do its ranking, and one possible downside is the lag in coming up with suggestions if your SQLite database gets too large. However, MCFLY_HISTORY_LIMIT is available to limit this growth.

I've only been using it for a couple of days, so I can't give a fair appraisal of it, but the concept makes me pretty hopeful: using extra information to customize tools towards real-world usage.

ℹ️ Install McFly

You can install McFly several ways. Here is brew: :

brew tap cantino/mcfly
brew install mcfly
Enter fullscreen mode Exit fullscreen mode

Then add hooks to your .zshrc, bashrc or equivalent:

eval "$(mcfly init zsh)"
Enter fullscreen mode Exit fullscreen mode

The fact that the binary emits the init script rather than dumping an init script into my home directory is a nice touch. zoxide - the following tool - does this as well.

I found that FZF was interfering with the CTRL-R of McFly and had to comment out this line in the FZF init script to get McFly working.

Better CD

zoxide

FZF works nicely for some path completions, but I didn't find it helpful when changing directories with cd: After typing cd **TAB from my home directory, it takes a while for FZF to build up the full list options. It was much faster to use my existing ZSH completions of cd TAB <choose a dir> TAB <choose a dir> to navigate to a folder.

However, many tools exist which attempt to improve upon cd. autojump, z, and Fasd all track directory usage and give you a single key shortcut for changing to commonly accessed directories. r/commandline has an detailed discussion of these various cd replacements, but the one that has the most momentum is zoxide. zoxide is a rewrite of z in Rust and promises improved speed.

After you install it, you can use it just like cd (z ~/path/foo/bar), but you can also change directories based on ranked text matches of the path (z bar ~= cd ~/path/foo/bar ). Instead of needing to supply the full path to change locations, you can instead provide a unique sub-string of the path, and zoxide will use its usage history to get you where you want.

For ease of adoption, I've chosen to have zoxide replace cd, which is as simple as using the --cmd flag when you add the initialization shell code (eval "$(zoxide init zsh --cmd cd)").

ℹ️ Install zoxide

zoxide can be installed several ways. Here is brew: :

brew install zoxide
Enter fullscreen mode Exit fullscreen mode

Then add hooks to your .zshrc, bashrc or equivalent:

eval "$(zoxide init zsh --cmd cd)"
Enter fullscreen mode Exit fullscreen mode

GitUpdate

This tool is another find from the Lobste.rs thread. When working on a git branch, I like to commit my work frequently. For example, before I try to delete some large block of text in a blog post, or before I attempt to refactor some piece of code, I commit my work. Of course, I'll squash, or restructure, these commits later on, but for convenience, I have a git alias called wip ('work in progress`) which gives me a low effort way to commit.


git wip = !git add --all; git ci -m WIP

gitupdate is a simple improvement on this idea. gitupdate . commits your files but uses the file names (but not extensions) of the changed files to create a more meaningful commit message. It's great for times when the commit message doesn't matter.

ℹ️ Install GitUpdate

bash
git clone https://github.com/nikitavoloboev/gitupdate
go build
sudo cp gitupdate /usr/local/bin

Other Tools

There are many other helpful command-line tools. More than can be covered well in a single article. JQ, mitmproxy, Pandoc, and PSTree are some I use frequently. There is also a whole class of Rust rewrites of common POSIX tools that warrant an article of their own.

Of course, Earthly itself is a command-line tool, and one I constantly use for gluing together various development steps together. It, and the tools I use for linting prose have become a standard part of how I work.

What less common command-line tools do you use? If you have tool suggestions, I'd love to hear them.

Top comments (9)

Collapse
 
ruanbekker profile image
Ruan Bekker

I simply cannot live without fzf

Collapse
 
adamgordonbell profile image
Adam Gordon Bell

It's surprisingly useful!

Collapse
 
adamgordonbell profile image
Adam Gordon Bell

What less common command-line tools do you use? If you have tool suggestions, I'd love to hear them.

Collapse
 
thefluxapex profile image
Ian Pride • Edited

I don't know how "less common" it is, but the fuck is one of my all time favorites that I didn't write. The rest of my favorite tools are ones in my own personal toolkits (in my quest to replace or, at least, supplement GNU just for the hell of it lol) that I wrote, so, of course, they are less common.

Collapse
 
adamgordonbell profile image
Adam Gordon Bell

I use fuck all the time, for doing git PR pushes. Great tool!

Collapse
 
melezhik profile image
Alexey Melezhik

Hi! Nice overview. Thank you. You might also take a look at Tomtit - Raku Task Runner.

Collapse
 
adamgordonbell profile image
Adam Gordon Bell

Thanks for reading! I'll check it out

Collapse
 
monadwizard profile image
Rakib Hasan

I think fish konsole is enough for all of that

Collapse
 
adamgordonbell profile image
Adam Gordon Bell

Like it replaces all these tools? I haven't used it myself/