Hypermodern Terminal Toolbox

All developers use terminals; for some, their entire workflow is in the terminal.

Prompt: 'computer terminal console screen and keyboard on a rainbow desk, style of guy billout, colorful'. Seed: 77.<br />Created with Stable Diffusion 1.
Prompt: 'computer terminal console screen and keyboard on a rainbow desk, style of guy billout, colorful'. Seed: 77.
Created with Stable Diffusion 1.

This post introduces the Hypermodern Terminal Toolbox - terminal, shell and command-line tools setting the standard in 2023.

Kitty as a Terminal Emulator

Kitty is a terminal emulator - it's an alternative to the GNOME Terminal, Alacritty or the Windows Terminal.

A terminal emulator is the program that runs your terminal. Different operating systems (OS) offer different terminal emulators, either as part of the OS or as installable third-party programs.

Kitty is a GPU-accelerated, third-party terminal emulator. Kitty is fast, highly customizable, and open source.

Configuration is done using a kitty.conf text file:

kitty.conf | text
font_family      Operator Mono Book
font_size 14.0
scrollback_lines 2000

Kitty offers extensive configuration of fonts, cursors, color scheme and keyboard shortcuts.

Tip - when changing Kitty settings in kitty.conf, you will need to fully restart the Kitty program.

Zsh & Prezto as a Shell

Zsh is a shell written in C - it's an alternative to Bash or Fish.

A shell is an operating system text interface that runs inside a terminal. Shell commands perform tasks like creating files and running programs.

Zsh is an open source shell, offering more functionality and customizability than Bash.

Zsh is configured using a .zshrc file:

~/.zshrc | bash
alias brew='arch -x86_64 brew'
export PATH="$HOME/dotfiles/scripts:$PATH"

Prezto is a configuration framework for Zsh - it's an alternative to Oh My Zsh.

Features of Prezto include syntax highlighting and command tab completion. Tab completion is useful for interactively exploring new command-line tools.

Prezto is configured using a .zpreztorc file:

~/.zpreztorc | bash
zstyle ':prezto:load' pmodule \
  'environment' \
  'terminal' \
  'editor' \
  'history' \
  'directory' \
  'spectrum' \
  'utility' \
  'completion' \
  'git' \
  'syntax-highlighting' \
  'history-substring-search' \
  'autosuggestions' \

Tip - Find a full list of Prezto modules here.

Neovim as a Text Editor

Neovim is a text editor written in C - it's an alternative to Vim, Nano or Emacs.

Neovim is a popular successor to Vim. The entire ecosystem of Vim plugins written in Vimscript works in Neovim, on top of a bustling ecosystem of Neovim plugins written in Lua.

A well-configured Neovim has language servers for autocompletion (the same language servers available in VS Code), syntax highlighting with Treesitter, and Telescope for searching through different types of lists.

Configuration of Neovim is done in Lua - starting with an init.lua file:

$XDG_CONFIG_HOME/nvim/init.lua | lua
--  set size of a tab to be 4
--  vim command line `:set tabstop=2`
--  vimscript `set tabstop=2`
vim.opt.set.tabstop = 2

--  run vimscript in lua
vim.cmd([[set tabstop=2]])

--  set variable
--  vimscript `let g:zoom#statustext = 'Z'`
vim.g['zoom#statustext'] = 'Z'

To match the full functionality of an IDE like VS Code, Neovim requires extension with plugins. You can set these up yourself; if you want to get set up quicker, you can use a distribution like AstroNvim, which comes with plugins installed.

Tip - subscribe to This Week in Neovim for a weekly newsletter covering the bustling Neovim ecosystem.

Tmux for Multiple Terminals

Tmux is a terminal multiplexer written in C - it's an alternative to Screen, or running terminals in multiple windows.

Terminal multiplexers allow you to manage multiple terminal sessions within a single window.

Tmux gives you persistent sessions, window and pane management with customizable key bindings.

Tmux uses a hierarchy of concepts to manage multiple terminals:

  • A pane is a rectangular area within a window. Each pane displays a separate terminal session.
  • A window is a full-screen container that holds one or more panes.
  • A session is a collection of one or more windows.

Tmux sessions can be created, attached, detached and reattached.

You can start a new Tmux session with tmux new:

#  create a session named `work`
$ tmux new -s work

Tmux can be used to restore your working environment on a remote machine. If your SSH connection drops, you can restore the exact combination and layout of terminal sessions you had before by reattaching to the Tmux session on the remote machine.

You can reattach to a running Tmux session with tmux attach:

#  reattach to last session
$ tmux attach

#  reattach to the session named `work`
$ tmux attach -t work

Tmux operates using a prefix key, which defaults to Ctrl-b. Tmux is used by first pressing the prefix, followed by a command key:

  • Ctrl-b c: Create a new window.
  • Ctrl-b n: Switch to the next window.
  • Ctrl-b p: Switch to the previous window.

Tmux is configured using a .tmux.conf file:

~/.tmux.conf | shell-session
set -g default-terminal "screen-256color"
setw -g mode-keys vi
set -g status-left "#[fg=green,bold]Session: #S #[fg=white,bold]| #[fg=yellow,bold]Window: #W"
set-option -g prefix C-a

Tip - extend Tmux with this list of plugins.

Starship for a Pretty Prompt

Starship is a shell prompt written in Rust - it's an alternative to Powerlevel10k or Pure.

A prompt is a customizable part of the command line that provides context such as the current directory or Git branch.

Starship gives you a fast, customizable prompt.

Configuration is done using a starship.toml file:

$XDG_CONFIG_HOME/starship.toml | toml
disabled = true

disabled = true

ahead = "↑"
behind = "↓"

truncation_length = 2

Tip - Take a look at the Starship Presets for inspiration about what you can do with Starship.

Ripgrep for Searching Text

Ripgrep is a text file searcher written in Rust - it's an alternative to grep or find.

Ripgrep's primary feature is speed - it's faster than alternative tools.

The basic use of Ripgrep is to search for a pattern in a directory:

$ rg 'pattern' ~/project

My alias for Ripgrep is using g, which searches for text through all files, returning the name of files that contain a pattern:

alias g='rg -l --hidden --smart-case --line-buffered'

You can use this alias as follows:

$ g 'some-pattern' some/directory

Tip - configure the --ignore, --hidden and --smart-case options to control what files you include in your search.

fzf for Fuzzy Searching

fzf is a fuzzy finder written in Go - it's an alternative to deterministic search.

fzf allows you to search using a fuzzy search algorithm that matches regex patterns on incomplete information. This allows search results to appear as you type, even with misspellings.

fzf can be run as a command-line program:

$ fzf

It can also used with a ** syntax combined with a TAB button press - this allows you to run fzf inside specific directories:

#  fuzzy search all files in the `work` directory
$ cat ~/work/** <TAB>

fzf is often used in other programs - Neovim, Zsh and Sad all offer integration with fzf through plugins.

fzf can be used with different search backends, such as find, grep or Ripgrep.

Tip - use Ripgrep as the fzf backend by setting the FZF_DEFAULT_COMMAND environment variable export FZF_DEFAULT_COMMAND='rg --files --hidden'.

Exa for Listing Files

Exa is a file-listing program written in Rust - it's an alternative to ls and tree.

A file listing program shows you lists of files and directories. Exa offers features such as icons, Git integration, and versatile sorting options.

Exa has a few different basic views:

#  list as a grid
$ exa -G
bp-historical-data  cities  data-science-south-data  predict-newspapers  README.md  titanic

#  list each item on one line
$ exa -1

#  list as a table - same as `ls -l`
$ exa -l
drwxr-xr-x   - adam 26 Apr 20:20 bp-historical-data
drwxr-xr-x   - adam 14 Feb 16:42 cities
drwxr-xr-x   - adam 26 Apr 20:25 data-science-south-data
drwxr-xr-x   - adam 28 Apr 14:52 predict-newspapers
.rw-r--r-- 124 adam 29 Apr 15:20 README.md
drwxr-xr-x   - adam 26 Apr 17:31 titanic

Exa can also replace the tree program, showing a recursive view of all files:

$ exa --tree --level=2
├── bp-historical-data
│  ├── __pycache__
│  ├── dashboard.py
│  ├── data
│  ├── notebooks
│  ├── README.md
│  └── requirements.txt
├── README.md
└── titanic
   ├── data
   ├── requirements.txt
   ├── titanic.ipynb
   ├── titanic.md
   └── titanic.py

Exa's configuration options for the long, tabular view (the equivalent of ls -l) are extensive - allowing a complete configuration of columns and sorting order of items.

My aliases for Exa are:

alias ls='exa --long --icons --no-permissions --no-user --git --time-style long-iso --time=modified --group-directories-first -a'
alias tree='exa --tree'

Tip - Try exa --sort=size --reverse to identify large files as a list sorted by size in descending order.

Bat for Viewing Files

Bat is a file viewer written in Rust - it's an alternative to cat.

A file viewer is a program that displays the contents of a file.

Bat offers functionality such as syntax highlighting, Git integration and automatic file paging.

Bat is used by pointing the program at a text file:

$ bat path/to/file

Tip - Customize the appearance with themes by using the --theme flag like bat --theme="TwoDark".

Sad for Replacing Text

Sad is a stream editor written in Rust - it's an alternative to sed or awk.

Stream editors perform search and replace operations on text streams or text files.

Sad (Space Age seD) will show proposed replacements before applying them, allowing you to check and select which replacements to make before committing them.

Sad is used as a command-line program:

$ sad '<pattern>' '<replacement>'

You can use Sad to replace text in a file or an input stream - below we replace the word course with module in a file README.md:

$ cat README.md
# Data Science South Projects

Example projects for the courses at [Data Science South](https://www.datasciencesouth.com/).

$ exa -1 | sad "courses" "modules"      

$ cat README.md
# Data Science South Projects

Example projects for the modules at [Data Science South](https://www.datasciencesouth.com/).

Tip - Use --commit to write replacements without an interactive preview.

jq for Working with JSON

jq is a JSON processor written in C - it's an alternative to fx, jp, or processing JSON in a language like Python.

jq allows you to filter, transform, and manipulate JSON data, which is useful for working with API responses, configuration files, and data stores.

A central idea in jq is the filter, which applied to the input JSON:

$ jq 'filter_expression' input.json

Some useful jq filters are (using the Python key/value language for dictionaries):

  • .key - extract the value of a key,
  • .[] - extract all values from an array,
  • .[2] - extract the third value from an array.

A few examples:

#  extract the `name` key
$ echo '{"name": "Alice", "data": [6, 12]}' | jq '.name'

#  extract the second element from the `data` list
$ echo '{"name": "Alice", "data": [6, 12]}' | jq '.data[1]'

Tip - You can pretty-print JSON data with cat input.json | jq.

zoxide for Navigation

zoxide is a terminal navigation utility written in Rust - it's an alternative to cd, pushd, and popd.

zoxide jumps to directories from your visit history. It assigns a score to each directory based on how frequently and recently they have been visited.

zoxide is used as a command line program:

#  move to a folder that best matches `code`
$ z code

Tip - use zoxide query -s -l to see the directories in your zoxide database.

Tig for Viewing Git History

Tig is a Git history viewer written in C - it's an alternative to using the Git CLI or Lazygit.

Tig provides a navigable, color-coded interface for browsing your Git commit history. It allows searching for commits, viewing the commit graph and showing files at a different point in time.

Tig is run as a command-line program:

$ tig

Tip - Press h while running Tig to access help & display available commands.

direnv for Environment Variable Management

direnv loads and unloads shell environment variables - written in Go, it's an alternative to using $ source .env.

direnv automatically loads & unloads environment variables as you navigate between different project directories.

Using direnv avoids manual loading of environment variables, and protects against environment variables from one project being set in another project.

direnv uses a .envrc file to hold variables specific to your project, which is run as a shell script:

.envrc | bash
export PROJECT_NAME="alpha"

Running direnv allow will whitelist the .envrc, authorizing the automatic use of this specific .envrc file:

$ direnv allow .

Now the PROJECT_NAME variable will be loaded and unloaded automatically when moving in and out of the project directory.

A common practice is to optionally load a secret or private .envrc:

source_env_if_exists .envrc.secret

If .envrc.secret exists, it will be loaded, otherwise it will be ignored.

Tip - Use direnv exec <path> <command> to run a command with the environment loaded for a specific directory without navigating to it.

Lazydocker for Docker

Lazydocker manages Docker containers and images - written in Go, it's an alternative to Docker Desktop or the Docker CLI.

Lazydocker makes it easy to view, start, stop, and remove containers and images through a terminal UI. It can also provide a real-time overview of container status, logs, and resource usage.

Lazydocker is used as a command-line program:

$ lazydocker

Tip - Press ? in Lazydocker to view a list of available keybindings and their corresponding actions.

Markserv for Previewing Markdown

Markserv renders Markdown files in a browser - written in Node.js, it's an alternative to Grip or Markdown Preview.

Markserv renders Markdown to HTML in real time, automatically reflecting changes as you make them.

Markserv supports GitHub flavored Markdown, which means it formats code blocks & tables the same as Github. Markserv is great for previewing README.md files without pushing to Github.

To start a Markserv server on port 8010:

$ markserv -p 8010

Tip - Use the --browser flag when starting Markserv to automatically open the served content in your default web browser.

Ngrok for Sharing Local Servers

ngrok creates tunnels to your local servers - written in Go, it's an alternative to Serveo, LocalTunnel, or PageKite.

ngrok exposes a local server behind a NAT or firewall to the internet. This is useful for sharing a development server with your team.

You can start a tunnel to port 8000 by running:

$ ngrok http 8000

Tip - To expose non-HTTP services, use the ngrok tcp or ngrok tls.


The Hypermodern Terminal Toolbox is:

  • Kitty for a GPU accelerated, highly customizable terminal,
  • Zsh for a shell & Prezto for Zsh configuration,
  • Neovim as a text editor,
  • Tmux for managing multiple terminals,
  • Starship for a pretty prompt,
  • Ripgrep for searching text files,
  • fzf for fuzzy searching,
  • Exa for listing files,
  • Bat for viewing files,
  • Sad for find and replace in text files,
  • jq for working with JSON,
  • zoxide for navigation,
  • Tig for viewing Git history,
  • direnv for environment variable management,
  • Lazydocker for Docker,
  • Markserv for previewing Markdown,
  • ngrok for exposing local servers to the internet.

Don't feel pressured to learn all these tools at once. Steadily learn one tool at a time to become a terminal master 🧙

Thanks for reading!

If you enjoyed this blog post, make sure to check out our free 77 data science lessons across 22 courses.