efficient terminal tools

In this post, I hope to give the best, most useful, and most practical terminal-based tools that I regularly use. These are the tools I wish someone had forced me to try years ago, so I hope to convince you to try them here.

This post was originally written for a presentation I gave to coworkers. I plan to update it over time with any new discoveries I make.


As I progressed in my education and experience as a software engineer, I received a lot of guidance as to how to improve how my software was structured. However, I was never really instructed on the process of creating that software. I moved between Eclipse, JetBrains, and VS Code without ever really learning how to navigate a codebase quickly, script programs together, or work with git beyond the dreaded:

git add . && git commit -m "changes" && git push
still a classic, but there is so much more

Later, I saw online what certain engineers and bash wizards were capable of. Certain things feel intractable—like mastering every awk and bash nuance. However, as I used the tools, I got more comfortable and began to move faster.

Additionally, there’s been an influx of usability improvements. As developer interest grows in languages like Rust and Zig, the chance to redesign from scratch has led to a new wave of excellent, easy-to-use tools.


prerequisite: you need a good tty #

I will cry if you run these in Command Prompt.

Terminal applications can only do so much if the surrounding terminal interface is poor.

For Linux and Mac, I highly recommend either kitty or ghostty. Both have excellent performance and support all the fancy terminal features. Namely, they work with the kitty terminal graphics protocol that lets you display images in the terminal!

For Windows, alacritty is the best native option I have found. Not quite as feature-rich in my experience, but the only tty of this class that is windows-native (that I have found).

Also important: Install a Nerd Font! Many programs depend on these for icons.


cht.sh #

When the maze of arguments and options are starting to slow you down, cht.sh is your best friend. At any terminal with internet access, you can use it to search for command-line tools and their usage.

Lets say you are trying to do a simple tar operation.

hugo

First, you can use it directly from your browser or through curl: curl cht.sh/tar

Or, you can install their command line client. I prefer this, as you don’t need to use URL syntax to search. I’ll run cht.sh tar:

 cheat:tar 
---
tags: [ compression ]
---
# To extract an uncompressed archive:
tar -xvf /path/to/foo.tar

# To extract a .tar in specified directory:
tar -xvf /path/to/foo.tar -C /path/to/destination/

# To create an uncompressed archive:
tar -cvf /path/to/foo.tar /path/to/foo/
...

 tldr:tar 
# tar
# Archiving utility.
# Often combined with a compression method, such as gzip or bzip2.
# More information: <https://www.gnu.org/software/tar>.

# [c]reate an archive and write it to a [f]ile:
tar cf path/to/target.tar path/to/file1 path/to/file2 ...

# [c]reate a g[z]ipped archive and write it to a [f]ile:
tar czf path/to/target.tar.gz path/to/file1 path/to/file2 ...
...
Truncated output of "cht.sh tar"

gh-copilot #

For the more complicated tasks, or for when you’re not even sure which command you need, I will often reach for the gh-copilot extension for gh.

I have this aliased to ?? in my terminal so I can quickly search for commands. I find this to be a lot more ergonomic than switching to something like Warp Terminal when I need to search how to use a single command. 1


ripgrep and fd #

When I speak of older tools getting a modern redesign, these are probably the prime examples.

fd and ripgrep are fantastic alternatives to find and grep, and are multithreaded by default. 2 They have become my default for scripting operations to find certain regex patterns and file names quickly.


gh #

This section is basically here to say: stop trying to script GitHub with curl!

gh provides a helpful wrapper over many GitHub APIs and git operations. This integration allows for commands like gh repo clone bizmythy/nixconf, which clones based on the GitHub repo name using your preference setting for SSH/HTTP. It also lets you make queries like gh repo list --visibility=public:

NAME                     DESCRIPTION              INFO              UPDATED
bizmythy/nixconf         Nix Configuration Files  public            about 1 hour ago
bizmythy/bizmythy.gi...                           public            about 2 hours ago
bizmythy/nixpkgs         Nix Packages collect...  public, fork      about 19 hours ago
bizmythy/typeracer-FPGA                           public, archived  about 4 days ago
bizmythy/hugo            The world’s fastest ...  public, fork      about 4 days ago
bizmythy/zed             configuration for ze...  public            about 5 days ago
...

gh can output as json, which can be used in scripting quite easily.


atuin #

One of the most aggravating thing about working in the terminal can be when you know you have run a command before but it can’t be found in your history. Maybe it was in another session, maybe your history ran out of space, or maybe it was run on a completely different machine.

atuin is a terminal history manager that aims to always capture the history of the commands you run. This means syncing across sessions, windows, different terminals, and even different devices if you choose.

It stores all of your command history in a local SQLite database and replaces your CTRL+R search with a fuzzyfind of that history database in a nice TUI.


lazygit and lazydocker #

lazygit and lazydocker are wonderful TUIs for git and docker respectively by @jesseduffield.

When you learn just a few keyboard shortcuts, you can really move quickly in these tools.

In both, the keybinds are nicely displayed for you at the bottom, but you can even use your mouse.

Both have almost entirely replaced most of the docker and git calls I would type out before. lazygit especially has completely changed how I work with git, as it allows for quickly selecting files to add, exclude, and discard from your working git changes to your commit.


vim #

I don’t mean to beat a dead horse, but I truly don’t understand why vi-style keybindings are not the industry standard.

I’m not adamant that you use full-fledged vim itself. VS Code has VSCodeVim, which works great most of the time. I use zed for my development, which has an extremely robust vim mode. Even emacs has “evil” mode.

Regardless, I highly recommend taking a week, or even a weekend, to just give the keybinds a try in your favorite editor. Once you summit the initial learning curve, you will really see the benefits. I was a doubter myself at first, but after trying it, I haven’t looked back.


nushell #

Nushell is my absolute favorite of these tools.

It is probably wrong to even call it a tool, as nu is a fully-fledged shell which can be in lieu of bash/zsh/fish. 3 The key feature that sets nu apart from these is Pipelines.

Pipelines are a lot like traditional piping of stdin to stdout, but in nu they can store structured data. These look a lot like json and are printed as nicely formatted tables. You can then leverage the nu language functional operators to do some fairly powerful things:

Here’s a nu script to get the Git-LFS files in a repo and sort by the ones using the most space.

#!/usr/bin/env nu

let lfs_file_data = (
  git lfs ls-files --size |
    detect columns -n |
    reject column1 |
    rename hash file size |
    update size {|row| $row.size | str substring 1..-2 | into filesize} |
    sort-by size
)

print $lfs_file_data

let total_size = ($lfs_file_data | get size | math sum)
print $"Total size: ($total_size)"

Here’s what the script output looks like:

╭─────┬────────────┬────────────────────────┬──────────╮
│   # │    hash    │          file          │   size   │
├─────┼────────────┼────────────────────────┼──────────┤
│   n │ 3wfaijoefw │ ...                    │   8.1 MB │
│ 334 │ 7e193593ce │ smallfile.txt          │   8.1 MB │
│ 335 │ 73a43c7901 │ lessbigfile.png        │  20.0 MB │
│ 336 │ b57b275ee0 │ bigfile.mp4            │  65.0 MB │
├─────┼────────────┼────────────────────────┼──────────┤
│   # │    hash    │          file          │   size   │
╰─────┴────────────┴────────────────────────┴──────────╯
Total size: 143.9 MB

The nice things here:

  • git lfs commands don’t have the ability to output json, but you can just pipe them into detect columns and it will figure the data structure out for you!
  • There is a first-class filesize datatype, which we convert a string to and sort by. I don’t even want to know the crazy scripting it would take to properly compare megabits with kilobytes without this.
  • The biggest selling point for me: I didn’t have to look up anything. No googling. No reading manpages. nu has a very high skill floor, and it can become very powerful if you take the time to read through the excellent Nushell Book.

Honorable Mentions #

These tools are more niche, but come in handy for specific tasks.

I have never had a good experience going to shady file type conversion websites. They are always slow, covered in ads, and usually don’t work.

For converting, cropping, editing, and re-encoding videos, use ffmpeg. For images, use imagemagick.

This isn’t a terminal tool, but for PDF arranging, try pdfarranger.

If you are working with docker images, dive is a great tool for inspecting and analyzing docker images. It has often highlighted issues I could not find with any other image analysis tool.

bat is just cat with syntax highlighting. I use it all the time, especially because it behaves exactly like cat if it detects it is being piped into another command.


  1. Warp Terminal is pretty cool, but it lacks a lot of the rendering features I have come to expect from my TTY and can have some compatibility issues with some TUI applications. ↩︎

  2. A capable user of GNU Parallel can make grep and find operations parallelized, which is useful in scripting. However, for most use cases, having these optimizations compiled in is very beneficial. ↩︎

  3. Similar to fish, nu is extremely not POSIX compliant, so copy-pasting or running scripts with nu as the interpreter are bound to fail often.

    Never set a non-POSIX shell as your system’s default shell. I set nu as the default program that launches when I start my TTY. ↩︎