Why JSON broke the line-oriented pipe
Pipes assume one record per line. JSON is nested. grep, cut, and awk can't follow a key into a sub-object. jq exists to make JSON pipeable — read from stdin, query with a small expression language, write JSON or text to stdout.
Identity and pretty-printing
jq '.' file.json = pretty-print and color (the identity filter). cat data.json | jq is the canonical "make this readable" command.
Selecting fields
jq '.name'— value ofnameat the top level.jq '.users[0].email'— first user's email.jq '.users[].email'— every user's email (one per line).jq '.users | length'— count.jq '.users | map(.email)'— array of emails.
Filtering
jq '.users[] | select(.active == true)'— active users.jq '.users[] | select(.age > 30) | .name'— names of users over 30.
Reshaping output
jq '{id: .id, name: .name}'— new object with subset.jq -r '.[].url'— raw output, no quotes (great for piping URLs into curl).jq -c '.'— compact, one JSON object per line (newline-delimited JSON, the streaming-friendly format).
Real-world combos
curl -s api.github.com/repos/cli/cli/issues \
| jq '.[] | {n: .number, title}' | head
kubectl get pods -o json \
| jq '.items[] | select(.status.phase != "Running") | .metadata.name'Both feed JSON from one tool into a structured filter and back to a human-readable result. That's pipes in 2026.