Skip to content

Modern CLI Tools Cheat Sheet

Under the hood: Most modern CLI tools (fd, ripgrep, bat, eza, dust) are written in Rust, which is why they are significantly faster than their C/shell predecessors. Ripgrep, for example, uses memory-mapped files and SIMD instructions for regex matching, making it 2-10x faster than grep -r on large codebases. These tools also respect .gitignore by default, which is why they feel faster in practice — they skip node_modules/, .git/, and other junk directories.

Tool Quick Reference

Classic Modern What it does better
find fd Faster, respects .gitignore, simpler syntax
grep -r rg (ripgrep) Multi-threaded, .gitignore-aware, fastest
cat bat Syntax highlighting, line numbers, git diff
ls eza (exa) Git status, icons, tree view
du dust Visual bar chart, sorted by size
cd zoxide (z) Frecency-based directory jumping
sed/awk (JSON) jq Native JSON processing
sed/awk (YAML) yq Native YAML processing
top btop/htop Better UI, mouse support, filtering
curl httpie JSON by default, colorized, simpler syntax

fd

fd pattern                    # Find files matching pattern
fd -e yaml                    # By extension
fd -t d config                # Directories only
fd -H .env                    # Include hidden files
fd -e yaml -x wc -l           # Execute command on each match
fd -e go --exclude vendor     # Exclude paths

ripgrep (rg)

rg 'pattern'                  # Recursive search
rg 'pattern' -t go            # Filter by file type
rg 'pattern' -g '*.yaml'     # Glob filter
rg 'pattern' -l              # Filenames only
rg 'pattern' -c              # Count per file
rg 'pattern' -C 3            # 3 lines context
rg 'pattern' -i              # Case insensitive
rg 'pattern' --no-ignore     # Include gitignored files
rg 'TODO|FIXME|HACK' -t py   # Multiple patterns

Name origin: jq stands for "JSON query" — it is essentially sed for JSON data. Created by Stephen Dolan in 2012. The . filter means "the current input" — think of it like . meaning "current directory" in a filesystem. Every jq expression is a filter that transforms input into output.

jq

# Basics
jq '.'                        # Pretty-print
jq '.key'                     # Extract field
jq '.items[]'                 # Iterate array
jq '.items[0]'                # First element
jq '.items | length'          # Count

# Filtering
jq '.items[] | select(.status == "Running")'
jq '.items[] | select(.count > 5)'

# Transform
jq '{name: .metadata.name, ns: .metadata.namespace}'
jq -r '.items[].metadata.name'   # Raw output (no quotes)
jq -S '.'                        # Sort keys

# kubectl integration
kubectl get pods -o json | jq -r '.items[].metadata.name'

yq

yq '.metadata.name' file.yaml          # Read field
yq -i '.spec.replicas = 5' file.yaml   # Edit in-place
yq -o json file.yaml                   # YAML → JSON
yq -P file.json                        # JSON → YAML
yq ea '. as $item ireduce ({}; . * $item)' *.yaml  # Merge files
yq '.spec.containers[0].image' deploy.yaml

Gotcha: jq -r (raw output) is critical for scripting — without it, strings come wrapped in quotes ("hello" vs hello), which breaks variable assignments and pipe chains. Always use -r when feeding jq output to other commands.

fzf

# Interactive file selection
vim $(fzf)
fzf --preview 'bat --color=always {}'

# Pipe anything into fzf
kubectl get pods -o name | fzf | xargs kubectl logs
git branch | fzf | xargs git checkout
history | fzf                          # Search history

# With key bindings (add to shell rc):
# Ctrl-T: file finder
# Ctrl-R: history search
# Alt-C: cd into directory

tmux

tmux new -s work              # New named session
tmux ls                       # List sessions
tmux attach -t work           # Reattach
tmux kill-session -t work     # Kill session

# Key bindings (prefix = Ctrl-b):
# c     new window       d     detach
# n/p   next/prev        %     split vertical
# "     split horizontal [     scroll mode
# z     zoom pane        x     kill pane
# ,     rename window    s     switch session

bat

bat file.yaml                 # View with syntax highlighting
bat -l yaml file.txt          # Force language
bat -r 10:20 file.yaml        # Lines 10-20 only
bat --diff file.yaml          # Show git changes
kubectl get pod x -o yaml | bat -l yaml  # As pager

Default trap: On Ubuntu/Debian, the fd package is named fd-find (binary: fdfind) and bat is named bat (binary: batcat) due to naming conflicts with existing packages. You need aliases: alias fd='fdfind' and alias bat='batcat'. This catches everyone the first time.

Install (Ubuntu/Debian)

# apt-based
sudo apt install fd-find bat ripgrep fzf jq tmux

# Aliases for apt package names
alias fd='fdfind'        # Ubuntu packages fd as fdfind
alias bat='batcat'       # Ubuntu packages bat as batcat

# cargo/go/pip installs
cargo install eza dust
pip install httpie yq
go install github.com/ajeetdsouza/zoxide@latest