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
findreplacement; respects .gitignore, regex by default (sharkdp/fd) - rg / ripgrep - fast
grep -rreplacement; multi-threaded, .gitignore-aware (BurntSushi/ripgrep) - fzf - general-purpose fuzzy finder; turns any list into an interactive menu (junegunn/fzf)
- bat -
catwith syntax highlighting, line numbers, git diff markers (sharkdp/bat) - jq - command-line JSON processor; filter, transform, extract (jqlang.github.io/jq)
- yq -
jqfor YAML/TOML files; essential for Kubernetes manifests (mikefarah/yq) - eza -
lsreplacement 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 -
dureplacement with visual bar charts, sorted by size (bootandy/dust) - delta -
diff/git diffwith syntax highlighting, side-by-side, word-level diffs (dandavison/delta) - htop/btop - interactive
topreplacements with tree view, filtering, graphs - tldr - simplified man pages with practical examples (tldr-pages/tldr)
- httpie/xh - human-friendly
curlreplacement; JSON by default, colorized - procs -
psreplacement 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 kubectl —
kubectl 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
cattobatand breaking pipes — usebat -pp(plain, no-pager) for pipe-safe output. - Forgetting
fdis installed asfdfindon Debian/Ubuntu — alias it in your.bashrc. - Using
rgpatterns that are actually fixed strings — userg -F "literal.string"to avoid regex interpretation. - Not setting
FZF_DEFAULT_COMMAND— without it, fzf usesfindinstead offd, losing .gitignore awareness. - Writing complex
jqwhenkubectl -o jsonpathsuffices 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).
findrequires explicit flags for all of these. -
Find all YAML files in the current directory tree.
-
fd -e yaml -e ymlorfd '\.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"orrg --files-with-matches "password" -
Search for a literal string containing dots (e.g., "api.v2.endpoint").
-
rg -F "api.v2.endpoint"— the-Fflag 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-zflag searches compressed files. -
How do you do a multiline search with ripgrep?
rg -U "start_pattern.*\nend_pattern"— the-Uflag 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_COMMANDand 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 .gitso fzf uses fd instead of the slowerfind, 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.jsonorcat file.json | jq . -
Extract the
.status.phasefield 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[]'andjq '.items'? .itemsreturns 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 --gitshows git status (modified, staged, untracked) inline with each file in the listing.eza -la --gitadds 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 rolesorz 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.
duoutputs 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 -sshows 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 useyq -ito add limits, or open the selected files in your editor.
Wiki Navigation¶
Related Content¶
- 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