Developer Terminal Toolkit — jq, HTTPie, fzf, ripgrep

Why Learn CLI Tools?

GUI tools are intuitive, but CLI tools are overwhelmingly superior in terms of automation, pipeline composition, and speed. Using a cooking analogy, GUI is like a microwave (convenient but limited), while CLI is like a knife and cutting board (once you’re skilled, you can prepare any dish).

This post covers four CLI tools that immediately boost day-to-day development productivity.

jq: The Swiss Army Knife for JSON

jq is a tool for parsing, filtering, and transforming JSON on the command line. It’s essential when analyzing API responses or processing JSON logs.

Installation

# macOS
brew install jq

# Ubuntu/Debian
sudo apt install jq

# Windows (scoop)
scoop install jq

Basic Usage

# Pretty print JSON
echo '{"name":"Alice","age":30}' | jq '.'
# Output:
# {
#   "name": "Alice",
#   "age": 30
# }

# Extract a specific field
echo '{"name":"Alice","age":30,"city":"Seoul"}' | jq '.name'
# Output: "Alice"

# Output without quotes (-r option)
echo '{"name":"Alice"}' | jq -r '.name'
# Output: Alice

# Filter arrays
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' | jq '.[] | select(.age > 27)'
# Output: {"name":"Alice","age":30}

# Transform into a new structure
echo '[{"first":"Alice","last":"Smith"},{"first":"Bob","last":"Jones"}]' | \
  jq '[.[] | {full_name: (.first + " " + .last), initial: .last}]'
# Output:
# [
#   { "full_name": "Alice Smith", "initial": "Smith" },
#   { "full_name": "Bob Jones", "initial": "Jones" }
# ]

Practical Example: Analyzing API Responses

# Extract repository info from the GitHub API
curl -s "https://api.github.com/users/torvalds/repos?per_page=5" | \
  jq '[.[] | {name: .name, stars: .stargazers_count, language: .language}]' | \
  jq 'sort_by(-.stars)'
# Output:
# [
#   { "name": "linux", "stars": 180000, "language": "C" },
#   ...
# ]

# Extract only errors from JSON logs
cat app.log | jq -r 'select(.level == "error") | "\(.timestamp) \(.message)"'
# Output: 2026-04-07T10:00:01 Database connection failed

# Access deeply nested fields
echo '{"data":{"users":[{"id":1,"profile":{"email":"a@b.com"}}]}}' | \
  jq '.data.users[0].profile.email'
# Output: "a@b.com"

HTTPie: A Modern Alternative to curl

HTTPie is a human-readable HTTP client. It lets you test APIs with more intuitive syntax than curl.

Installation

# macOS
brew install httpie

# pip (all platforms)
pip install httpie

# Ubuntu
sudo apt install httpie

Basic Usage

# GET request (protocol and method can be omitted)
http httpbin.org/get
# Output: (auto-colored + formatted JSON response)

# POST request + JSON body (= separator for key-value pairs)
http POST httpbin.org/post name=Alice age:=30 active:=true
# name=value → string
# age:=30 → number (: prefix for JSON types)
# active:=true → boolean

# Add headers (: separator)
http GET api.example.com/users \
  Authorization:"Bearer eyJhbGci..." \
  Accept:application/json

# File upload
http --form POST api.example.com/upload file@./document.pdf

# Form data submission
http --form POST api.example.com/login username=admin password=1234

Comparison with curl

# POST request with curl
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer token123" \
  -d '{"name":"Alice","age":30}'

# Same request with HTTPie (much more concise)
http POST api.example.com/users \
  name=Alice age:=30 \
  Authorization:"Bearer token123"
FeaturecurlHTTPie
JSON formattingManual (| jq)Automatic
Color outputNoneAutomatic
JSON body-d '{"key":"val"}'key=val
Add headers-H "Key: Val"Key:Val
File upload-F "file=@path"file@path

Session Feature

# Save session — persist cookies/headers
http --session=myapi POST api.example.com/login username=admin password=1234
# Login cookies are saved to the session

# Reuse session in subsequent requests (auth info included automatically)
http --session=myapi GET api.example.com/profile
# Cookies are sent automatically

fzf: Fuzzy Finder

fzf is a tool that enables real-time fuzzy search on any list. Find files, history, branches, and anything else quickly.

Installation

# macOS
brew install fzf
$(brew --prefix)/opt/fzf/install  # Set up key bindings

# Ubuntu
sudo apt install fzf

# Install directly from Git
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install

Basic Usage

# Search for files in the current directory
fzf
# Type: "comp"
# Matches: src/components/Button.tsx, docker-compose.yml, ...
# Use arrow keys to select, Enter to confirm

# Combine with pipes
cat package.json | jq -r '.dependencies | keys[]' | fzf
# Fuzzy search through npm package list

# File search with preview
fzf --preview 'cat {}'
# Preview selected file contents on the right

# Select multiple items (Tab to select, Enter to confirm)
fzf --multi

Shell Integration (Key Feature)

# Key bindings automatically configured during fzf installation

# Ctrl+R — fuzzy search through command history (most used!)
# Before: history | grep docker → slow
# With fzf: Ctrl+R → type "docker" → instant find

# Ctrl+T — fuzzy search files/directories in current directory
# vim Ctrl+T → select file → open in vim

# Alt+C — fuzzy search directories then cd
# Alt+C → "comp" → cd to src/components/

Combining with Git

# Fuzzy search git branches then checkout
git branch -a | fzf | xargs git checkout

# Search commits in git log
git log --oneline | fzf --preview 'git show {1}'
# Preview diff based on commit hash

# Select changed files to add
git status -s | fzf --multi | awk '{print $2}' | xargs git add

# Register as a shell function (~/.bashrc or ~/.zshrc)
# Fuzzy git branch checkout
gbf() {
  local branch
  branch=$(git branch -a | sed 's/^..//' | sed 's|remotes/origin/||' | sort -u | fzf)
  if [ -n "$branch" ]; then
    git checkout "$branch"
  fi
}

ripgrep (rg): An Ultra-Fast grep Alternative

ripgrep is a grep alternative optimized for code search. It automatically respects .gitignore, recursively searches by default, and is 2-5x faster than grep.

Installation

# macOS
brew install ripgrep

# Ubuntu
sudo apt install ripgrep

# Windows (scoop)
scoop install ripgrep

# cargo (Rust)
cargo install ripgrep

Basic Usage

# Recursive search in current directory (default behavior)
rg "TODO"
# Output:
# src/app.ts:42:  // TODO: Add error handling
# src/utils.ts:15: // TODO: Implement caching

# Case-insensitive search
rg -i "error"

# Filter by file type
rg "import" --type ts          # TypeScript files only
rg "def " --type py            # Python files only
rg "SELECT" --type sql         # SQL files only

# Search in a specific directory
rg "useState" src/components/

# Regex search
rg "console\.(log|warn|error)" --type ts
# Find console.log, console.warn, and console.error

# Output only matching filenames
rg -l "TODO"
# Output:
# src/app.ts
# src/utils.ts

Advanced Usage

# Show context lines (2 lines above and below)
rg "error" -C 2

# Exclude specific patterns
rg "import" --type ts --glob '!**/*.test.ts'  # Exclude test files

# JSON output (for combining with other tools)
rg "TODO" --json | jq 'select(.type == "match") | .data.lines.text'

# Count matches per file
rg -c "console.log" --type ts | sort -t: -k2 -rn
# Output: (sorted by number of console.log occurrences)
# src/debug.ts:15
# src/app.ts:8
# src/utils.ts:3

# Replace (preview only, does not modify files)
rg "old_function" --replace "new_function"

# Speed comparison with grep (on large projects)
# grep -r "pattern" .    → about 3 seconds
# rg "pattern"           → about 0.3 seconds (10x faster)

fzf + ripgrep Combo

# Search with ripgrep + select with fzf + open in editor
rg --line-number "TODO" | fzf --delimiter : --preview 'cat -n {1} | head -{2}' | \
  awk -F: '{print "+" $2, $1}' | xargs code -g
# Fuzzy search TODO lines, then open the selected line in VS Code

# Interactive ripgrep (real-time search in fzf)
rg_fzf() {
  rg --line-number --color=always "$1" | \
    fzf --ansi --delimiter : \
        --preview 'cat -n {1}' \
        --preview-window 'right:60%'
}
# Usage: rg_fzf "pattern"

Tool Combination Cheat Sheet

# Extract specific fields from API response then fuzzy select
http GET api.example.com/users | jq -r '.[].name' | fzf

# Search error patterns in log files then check context
rg "ERROR" logs/ -C 3 | fzf --ansi

# Search processes then kill
ps aux | fzf | awk '{print $2}' | xargs kill

# Find JSON files + search contents
rg -t json "api_key" | fzf

Installation Summary

ToolmacOSUbuntuWindowsPurpose
jqbrew install jqapt install jqscoop install jqJSON processing
HTTPiebrew install httpieapt install httpiepip install httpieHTTP client
fzfbrew install fzfapt install fzfscoop install fzfFuzzy search
ripgrepbrew install ripgrepapt install ripgrepscoop install ripgrepCode search

Practical Tips

  • Start with Ctrl+R (fzf history search): This alone dramatically improves terminal productivity. No more retyping long commands.
  • jq is essential for API testing: Use curl ... | jq '.data' to instantly parse API responses and view specific fields.
  • Use rg instead of grep -r: It automatically respects .gitignore, skipping node_modules and dist folders, and is much faster.
  • Combine tools: Connecting tools with pipes (|) combines each tool’s strengths. Combos like rg | fzf, curl | jq | fzf are extremely powerful.
  • Create shell functions/aliases: Register frequently used combinations as functions in ~/.bashrc or ~/.zshrc to perform complex tasks with a single command.
  • Install bat alongside these tools: Using bat instead of cat gives you syntax-highlighted file contents, making fzf previews much more useful.

Was this article helpful?