Skip to content

Portal | Level: L0: Entry | Topics: jq / JSON Processing, ripgrep (rg), fzf, fd | Domain: CLI Tools

Modern CLI Tools - Skill Check

Mental model

Classic Unix tools (find, grep, cat, ls, du, cd) are universal but show their age. A new generation of tools — mostly written in Rust — provides the same functionality with better defaults, speed, and UX. These aren't toys; they're increasingly standard in DevOps workflows and pair naturally with Kubernetes, Terraform, and CI/CD tooling.

Visual stack

[Power workflows   ]  Combine tools: rg | fzf --preview 'bat {}' | xargs vim
|
[Interactive       ]  fzf (fuzzy finder), htop/btop (process viewer)
|
[Processing        ]  jq (JSON), yq (YAML), delta (diff)
|
[Finding           ]  fd (files), rg (content), procs (processes)
|
[Viewing           ]  bat (files), eza (directories), dust (disk), tldr (man)
|
[Navigation        ]  zoxide (smart cd)
|
[Shell config      ]  Aliases, FZF_DEFAULT_COMMAND, shell integration (eval "$(zoxide init bash)")

Glossary (jargon explained)

  • fd - fast find replacement; respects .gitignore, regex by default (sharkdp/fd)
  • rg / ripgrep - fast grep -r replacement; multi-threaded, .gitignore-aware (BurntSushi/ripgrep)
  • fzf - general-purpose fuzzy finder; turns any list into an interactive menu (junegunn/fzf)
  • bat - cat with syntax highlighting, line numbers, git diff markers (sharkdp/bat)
  • jq - command-line JSON processor; filter, transform, extract (jqlang.github.io/jq)
  • yq - jq for YAML/TOML files; essential for Kubernetes manifests (mikefarah/yq)
  • eza - ls replacement with tree view, git status, icons (eza-community/eza, successor to exa)
  • zoxide - smart cd; learns from usage, frecency-based directory jumping (ajeetdsouza/zoxide)
  • dust - du replacement with visual bar charts, sorted by size (bootandy/dust)
  • delta - diff/git diff with syntax highlighting, side-by-side, word-level diffs (dandavison/delta)
  • htop/btop - interactive top replacements with tree view, filtering, graphs
  • tldr - simplified man pages with practical examples (tldr-pages/tldr)
  • httpie/xh - human-friendly curl replacement; JSON by default, colorized
  • procs - ps replacement with color, search, tree view, port display
  • frecency - ranking algorithm combining frequency and recency (used by zoxide)

Core patterns you should know

  • Pipe into fzf — any command that outputs a list becomes interactive: kubectl get pods | fzf
  • rg + fzf + bat — the power trio: search code, fuzzy-filter results, preview with highlighting
  • jq for kubectlkubectl get pods -o json | jq '.items[] | select(..) | ...' replaces complex -o jsonpath
  • yq for manifests — read/update YAML fields without manual editing: yq -i '.spec.replicas = 5' deploy.yaml
  • delta as git pager — once configured (git config --global core.pager delta), all git diff/log/show gets highlighting

Common mistakes

  • Aliasing cat to bat and breaking pipes — use bat -pp (plain, no-pager) for pipe-safe output.
  • Forgetting fd is installed as fdfind on Debian/Ubuntu — alias it in your .bashrc.
  • Using rg patterns that are actually fixed strings — use rg -F "literal.string" to avoid regex interpretation.
  • Not setting FZF_DEFAULT_COMMAND — without it, fzf uses find instead of fd, losing .gitignore awareness.
  • Writing complex jq when kubectl -o jsonpath suffices for simple extractions.

fd — find replacement (easy -> hard)

  • How does fd differ from find in its defaults?
  • fd is recursive by default, respects .gitignore, uses regex patterns, has colorized output, and is case-insensitive for lowercase patterns (smart case). find requires explicit flags for all of these.

  • Find all YAML files in the current directory tree.

  • fd -e yaml -e yml or fd '\.ya?ml$'

  • Find all Dockerfiles (any name variation like Dockerfile, Dockerfile.dev, etc.).

  • fd -g 'Dockerfile*'

  • Find files larger than 100MB.

  • fd -S +100M

  • Find files modified in the last hour.

  • fd --changed-within 1h

  • Find all shell scripts and run shellcheck on each.

  • fd -e sh -x shellcheck

  • What flag makes fd include files ignored by .gitignore?

  • fd -I (or --no-ignore). For also showing hidden files: fd -IH.

ripgrep — grep replacement (easy -> hard)

  • What makes ripgrep faster than grep -r?
  • Multi-threaded by default, respects .gitignore (skips vendor/node_modules/etc.), uses an optimized regex engine (Rust's regex crate), and memory-maps files. On large codebases it can be 5-50x faster.

  • Search for the word "TODO" in all Python files.

  • rg -t py "TODO"

  • List only filenames containing "password" (no line content).

  • rg -l "password" or rg --files-with-matches "password"

  • Search for a literal string containing dots (e.g., "api.v2.endpoint").

  • rg -F "api.v2.endpoint" — the -F flag disables regex so dots are literal.

  • Find all hardcoded IP addresses in the codebase.

  • rg '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'

  • Search inside compressed log files.

  • rg -z "ERROR" /var/log/syslog.gz — the -z flag searches compressed files.

  • How do you do a multiline search with ripgrep?

  • rg -U "start_pattern.*\nend_pattern" — the -U flag enables multiline mode.

fzf — fuzzy finder (easy -> hard)

  • What three shell keybindings does fzf add?
  • Ctrl-R: fuzzy search command history. Ctrl-T: fuzzy find files and insert path. Alt-C: fuzzy find directories and cd into selected one.

  • How do you add a preview window to fzf?

  • fzf --preview 'bat --color=always {}' — shows file contents with syntax highlighting as you browse.

  • Select a Kubernetes pod interactively and tail its logs.

  • kubectl get pods | fzf | awk '{print $1}' | xargs -I{} kubectl logs -f {}

  • Select a git branch interactively and check it out.

  • git branch -a | fzf | sed 's/remotes\/origin\///' | xargs git checkout

  • How do you pipe ripgrep results into fzf with a preview of the matching file?

  • rg --line-number "pattern" | fzf --delimiter ':' --preview 'bat --color=always --highlight-line {2} {1}'

  • What is FZF_DEFAULT_COMMAND and why should you set it?

  • It controls what command fzf uses to generate its file list. Set it to fd --type f --hidden --follow --exclude .git so fzf uses fd instead of the slower find, and respects .gitignore.

bat — cat replacement (easy -> hard)

  • What does bat add over cat?
  • Syntax highlighting for 200+ languages, line numbers, git diff markers (shows changed lines), automatic paging (like less), and file header with filename.

  • View lines 50-100 of a file with bat.

  • bat -r 50:100 file.py

  • Use bat without paging or decoration (pipe-safe mode).

  • bat -pp file.txt — plain output, no paging. Safe for piping to other commands.

  • How do you use bat as your man pager?

  • export MANPAGER="sh -c 'col -bx | bat -l man -p'" in your .bashrc.

  • How do you highlight Kubernetes YAML output from kubectl?

  • kubectl get deploy nginx -o yaml | bat -l yaml

jq — JSON processor (easy -> hard)

  • Pretty-print a JSON file.
  • jq . file.json or cat file.json | jq .

  • Extract the .status.phase field from kubectl pod JSON.

  • kubectl get pod nginx -o json | jq '.status.phase'

  • List the names of all pods in a namespace.

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

  • Find all pods that are NOT in Running state.

  • kubectl get pods -o json | jq -r '.items[] | select(.status.phase != "Running") | .metadata.name'

  • Output pod name, phase, and IP as a TSV table.

  • kubectl get pods -o json | jq -r '.items[] | [.metadata.name, .status.phase, .status.podIP] | @tsv'

  • Extract resource requests and limits for all containers.

  • kubectl get pods -o json | jq -r '.items[] | .metadata.name as $pod | .spec.containers[] | [$pod, .name, .resources.requests.cpu // "none", .resources.limits.cpu // "none"] | @tsv'

  • Merge two JSON files (base + override).

  • jq -s '.[0] * .[1]' base.json override.json — the -s (slurp) reads both files into an array, * does recursive merge.

  • What's the difference between jq '.items[]' and jq '.items'?

  • .items returns the array as a single JSON array. .items[] iterates over the array, outputting each element as a separate JSON value. The [] is the array iterator.

eza — ls replacement (easy -> hard)

  • How do you get a tree view with git status?
  • eza --tree --level=2 --git --icons

  • Sort files by size (largest first).

  • eza -la --sort=size --reverse

  • Show only directories.

  • eza -D

  • What advantage does eza have over ls for a git repository?

  • eza --git shows git status (modified, staged, untracked) inline with each file in the listing. eza -la --git adds a git status column to the long format.

zoxide — cd replacement (easy -> hard)

  • How does zoxide decide which directory to jump to?
  • Frecency algorithm: a combination of frequency (how often you visit) and recency (how recently you visited). Directories you visit often and recently rank highest.

  • You've been working in /home/user/projects/grokdevops/devops/ansible/roles. How do you get back from anywhere?

  • z roles or z ansible — zoxide matches the highest-frecency directory containing that substring.

  • How do you use zoxide interactively (fuzzy search all known directories)?

  • zi — opens an interactive fzf-like picker of all tracked directories.

  • How do you remove a deleted directory from zoxide's database?

  • zoxide remove /path/to/deleted/dir

dust — du replacement (easy -> hard)

  • What does dust show that du doesn't by default?
  • Visual bar charts proportional to size, sorted by size (largest at bottom), colorized, and shows both apparent and actual disk usage. du outputs plain text, unsorted.

  • Check what's eating space in /var.

  • dust /var

  • Show only the top 10 largest entries, 2 levels deep.

  • dust -n 10 -d 2

  • What's the difference between apparent size and actual disk size?

  • Apparent size is the file's logical size (what applications see). Actual size is disk blocks consumed (affected by filesystem block size, sparse files, compression). A 1-byte file has 1 byte apparent size but typically 4KB actual size (one block). Sparse files can have large apparent size but tiny actual size. dust -s shows apparent size.

Combination patterns (hardest)

  • Describe the rg + fzf + bat workflow for interactive code search.
  • rg --line-number "pattern" | fzf --delimiter ':' --preview 'bat --color=always --highlight-line {2} {1}' — ripgrep finds all matches with line numbers, fzf lets you fuzzy-filter the results interactively, bat shows a highlighted preview of the matching file with the match line highlighted. Select a result to get the file:line reference.

  • Write a shell function that fuzzy-selects a Kubernetes pod and runs a given kubectl command on it.

  • fpod() { local ns pod; read -r ns pod _ <<< "$(kubectl get pods -A | fzf | awk '{print $1, $2}')"; [ -n "$pod" ] && kubectl "$@" "$pod" -n "$ns"; } — Usage: fpod logs -f, fpod describe pod, fpod exec -it -- bash.

  • How would you set up your shell so that all these tools work together seamlessly?

  • 1) Install all tools (brew or cargo). 2) Set aliases: ls=eza, cat=bat -pp, grep=rg, find=fd, du=dust. 3) Configure fzf: FZF_DEFAULT_COMMAND='fd --type f --hidden --exclude .git', set preview to bat. 4) Init zoxide: eval "$(zoxide init bash)". 5) Set delta as git pager: git config --global core.pager delta. 6) Source fzf keybindings. 7) Add custom functions (fkill, fpod, fco) to .bashrc.

  • You need to find all Kubernetes deployments across 20 YAML files that have no resource limits set, then fix them. How would you approach this with modern CLI tools?

  • rg -l 'kind: Deployment' -t yaml | while read -r f; do yq '.spec.template.spec.containers[] | select(.resources.limits == null)' "$f" 2>/dev/null | grep -q . && echo "$f"; done | fzf --preview 'bat --color=always {}' --multi — finds YAML files containing Deployments, filters for those missing resource limits, lets you fuzzy-select which to edit. Then use yq -i to add limits, or open the selected files in your editor.

Wiki Navigation

  • Modern CLI Tools (Topic Pack, L0) — fd, fzf, jq / JSON Processing
  • Modern CLI Drills (Drill, L0) — fzf, jq / JSON Processing, Modern CLI Tools
  • CLI Tools Flashcards (CLI) (flashcard_deck, L1) — Modern CLI Tools
  • Modern CLI Flashcards (CLI) (flashcard_deck, L1) — Modern CLI Tools
  • Ripgrep Flashcards (CLI) (flashcard_deck, L1) — ripgrep (rg)
  • YAML, JSON & Config Formats (Topic Pack, L1) — jq / JSON Processing
  • fd (Topic Pack, L1) — fd
  • fd Flashcards (CLI) (flashcard_deck, L1) — fd
  • fzf (Topic Pack, L1) — fzf
  • fzf Flashcards (CLI) (flashcard_deck, L1) — fzf