Skip to content
shellmap

jqFilter, transform, and build JSON from the shell with a tiny query DSL across all 5 shells

Equivalents in every shell

Bashunix
curl -s https://api.example.com/users | jq '.[] | .name'

Selectors: `.` (identity), `.field` (property), `.[0]` (array index), `.[]` (iterate), `select(...)` (filter), `|` (pipe), `to_entries` / `from_entries` (object reshape). `-r` strips quotes for raw string output when feeding shell tools; `-c` emits one-line compact JSON; `-n` builds from scratch with `--arg`/`--argjson`.

Zshunix
curl -s https://api.example.com/users | jq '.[] | .name'

Same external `jq`. Not in base macOS — `brew install jq`. Zsh's `${(f)var}` line-split modifier turns `jq -r`'s newline-separated output into a zsh array: `users=("${(@f)$(jq -r .[].name <users.json)}")`.

Fishunix
curl -s https://api.example.com/users | jq '.[] | .name'

Same external `jq`. Fish's `string split \n` pairs cleanly with `jq -r` output to produce a fish list iterable via `for x in (jq -r .[].name <users.json | string split \n)`.

PowerShellwindows
Invoke-RestMethod https://api.example.com/users | ForEach-Object { $_.name }

PowerShell's `Invoke-RestMethod` + property-access pipeline is the native equivalent — no separate parser binary. `ConvertFrom-Json` exposes the same model from a string input. For complex queries that mirror `jq`'s DSL, install jq directly: `winget install jqlang.jq`. Property access is case-INSENSITIVE; jq is case-sensitive.

cmd.exewindows
curl -s https://api.example.com/users | jq ".[] | .name"

Windows 10 1803+ ships `curl.exe`; `jq` needs separate install via `winget install jqlang.jq` or `choco install jq`. Inside cmd.exe, double-quote the jq expression (`".[]"`) — single quotes don't group in cmd, and `%` chars must be doubled (`%%`).

Worked examples

Filter an array of objects by property

Bash
jq '.[] | select(.role == "admin") | .name' users.json
PowerShell
(Get-Content users.json | ConvertFrom-Json) | Where-Object role -eq admin | Select-Object -ExpandProperty name
cmd.exe
jq ".[] | select(.role == \"admin\") | .name" users.json

Build a new JSON object from shell variables

Bash
jq -n --arg name alice --argjson age 30 '{name: $name, age: $age, created: now | todate}'
PowerShell
@{name='alice'; age=30; created=([DateTime]::UtcNow).ToString("o")} | ConvertTo-Json

Reshape every object in an array (rename + add computed field)

Bash
jq '[.[] | {id, fullName: (.first + " " + .last)}]' users.json
PowerShell
(Get-Content users.json | ConvertFrom-Json) | ForEach-Object { [PSCustomObject]@{id=$_.id; fullName="$($_.first) $($_.last)"} } | ConvertTo-Json

Gotchas

  • Default output is JSON (quoted strings, escaped); `-r` (raw) strips the surrounding quotes — essential when piping to other shell tools that don't want a `"value"` literal. Forgetting `-r` is the #1 newcomer trap (e.g. `cd $(jq .path config.json)` will try to `cd` into `"some/path"` with literal quotes).
  • `jq` is case-SENSITIVE on property names (matches the JSON spec). PowerShell's `[PSCustomObject]` is case-INSENSITIVE by default — porting `jq` queries to `Where-Object` may produce different behaviour if your JSON has same-letter different-case keys. Use `ConvertFrom-Json -AsHashtable` (pwsh 6+) for case-sensitive equivalence.
  • Filter expressions are NOT general-purpose JavaScript — `jq` has its own DSL (closer to XPath). `.field?` (optional) silently skips missing keys; `.field` errors. `|=` (update assignment), `//` (alt default), `?` (optional path), and `try ... catch` are jq-specific and have no jq-to-JavaScript translation.
  • Streaming mode (`--stream` / `--stream-errors`) is mandatory for JSON files larger than RAM. Without it, jq buffers the entire input — a 5GB JSON file at default settings can OOM a 4GB container. `--stream` emits `[path, value]` tuples — different processing pattern but constant memory.
  • jq 1.7 (2023) changed module loading syntax (`include "file";` instead of `include "file" {};`) and added `pick`, `getpath`, and `splits` builtins. Older Ubuntu LTS ships jq 1.6 — scripts using new builtins fail with `jq: error: pick/1 is not defined`. Pin jq version in CI / Dockerfiles.

WSL & PowerShell Core notes

pwshNative PowerShell pipeline (`Where-Object` / `ForEach-Object` / `Select-Object`) covers most jq use cases without an external binary, but lacks jq's reshape DSL (`to_entries`, `from_entries`, complex path manipulation) and `--stream` for huge files. For pSEO portability, install jq cross-platform: `winget install jqlang.jq` (Windows) / `brew install jq` (macOS) / `apt install jq` (Debian/Ubuntu) / `dnf install jq` (Fedora/RHEL).
WSLjq runs ~10× faster reading files from the WSL2 native filesystem (`~/`) than from `/mnt/c/...` (DrvFs overhead). For one-off Windows-side JSON lookups, the speed hit is negligible; for pipelines processing thousands of files, copy to `~/` first or invoke jq from PowerShell via the Windows-installed binary.

Common tasks using jq

Related commands