Guia rápido do jq: 30 padrões JSON de linha de comando reais
Você direciona kubectl get pods -o json para o less, e o terminal trava diante de dois megabytes de JSON. Tudo o que você quer é o nome de cada pod na fase Running. O jq faz isso com três caracteres de filtro — desde que você conheça o vocabulário.
Este não é mais um guia de sintaxe. São 30 padrões que você realmente vai digitar, agrupados pela tarefa que está tentando resolver: acessar, filtrar, transformar, agregar, formatar e combinar com ferramentas reais como kubectl, aws e docker.
Quando usar jq, formatador de navegador ou código
jq nem sempre é a resposta certa. As três escolhas honestas são:
| Situação | Ferramenta ideal | Por quê |
|---|---|---|
| Uma resposta de API, com realce de sintaxe e números de linha | JSON Formatter no navegador | Diff visual, zero configuração, privado no navegador |
| Pipeline de shell, processamento de logs, script de CI, servidor remoto | jq | Componível, scriptável, sem dependência de GUI |
| Lógica de negócio, testes unitários, ramificações complexas | Código (JS / Python) | Debugger real, tipagem, bibliotecas |
Escolha jq quando a tarefa vive dentro de um pipeline de shell — o resto geralmente fica mais fácil em outro lugar.
Instalação e seu primeiro pipeline
O jq chega como binário único em todas as plataformas principais:
# macOS
brew install jq
# Debian / Ubuntu
sudo apt install jq
# Windows (winget)
winget install jqlang.jq
Primeiro pipeline, usando o filtro identidade:
curl -s https://api.github.com/users/octocat | jq .
O filtro . pega a entrada e a devolve inalterada, formatada. Só isso já substitui a maioria dos momentos «deixa eu abrir esse JSON em um editor».
Cinco flags cobrem 90 % do uso real:
| Flag | Função |
|---|---|
-r | Saída crua — remove aspas ao redor de resultados de string |
-c | Compacto — um valor JSON por linha (NDJSON) |
-s | Slurp — lê todas as entradas em um único array |
-R | Entrada crua — lê linhas como strings em vez de JSON |
-n | Entrada nula — não lê stdin, usa null como entrada |
O modelo mental central: filtros e pipes
Um filtro recebe um valor JSON como entrada e produz zero ou mais valores JSON como saída. Filtros compõem-se com um pipe |, que envia cada saída do filtro da esquerda como entrada para o da direita. É o mesmo modelo mental de pipes de shell, só que correm valores JSON em vez de bytes.
# . — identidade
echo '{"name":"Alice"}' | jq '.'
# .key — acesso a campo
echo '{"name":"Alice"}' | jq '.name'
# .key.sub — caminho profundo
echo '{"user":{"email":"a@x.com"}}' | jq '.user.email'
# .[] — iterar elementos do array (produz múltiplas saídas)
echo '[{"id":1},{"id":2}]' | jq '.[] | .id'
# Composição com pipe: cada saída de .items[] alimenta .name
echo '{"items":[{"name":"a"},{"name":"b"}]}' | jq '.items[] | .name'
Toda a gramática cabe aqui. Os 30 padrões abaixo são combinações dessas primitivas.
30 padrões que você vai usar de verdade
Cada padrão mostra o JSON de entrada, o comando e a saída. Copie qualquer um direto para o terminal.
Acesso e extração (padrões 1–5)
Padrão 1 — Acesso seguro com ?
Acessar um campo que pode não existir, sem quebrar:
echo '{"name":"Alice"}' | jq '.address?.city?'
# Saída: null
O ? suprime erros em chaves ausentes. Sem ele, .address.city lançaria erro de tipo se .address estivesse faltando.
Padrão 2 — Acesso por caminho profundo
echo '{"user":{"profile":{"email":"a@x.com"}}}' | jq '.user.profile.email'
# Saída: "a@x.com"
Padrão 3 — Fatiamento de array
echo '[10,20,30,40,50]' | jq '.[1:3]'
# Saída: [20, 30]
echo '[10,20,30,40,50]' | jq '.[-1]'
# Saída: 50
Índices negativos contam do fim. Fatias usam intervalos semiabertos, como em Python.
Padrão 4 — Descida recursiva para encontrar toda chave correspondente
echo '{"a":{"name":"x"},"b":[{"name":"y"},{"id":1}]}' | jq '.. | .name? | select(. != null)'
# Saída: "x"
# "y"
.. percorre todos os valores da árvore. Combinado com .name? e select, extrai cada campo name em qualquer profundidade — indispensável ao explorar esquemas JSON desconhecidos.
Padrão 5 — Listar todas as chaves de um objeto
echo '{"zebra":1,"apple":2,"mango":3}' | jq 'keys'
# Saída: ["apple", "mango", "zebra"]
echo '{"zebra":1,"apple":2,"mango":3}' | jq 'keys_unsorted'
# Saída: ["zebra", "apple", "mango"]
keys ordena alfabeticamente; keys_unsorted preserva a ordem de inserção.
Filtrar (padrões 6–10)
Padrão 6 — Filtrar array por condição
echo '[{"age":20},{"age":30},{"age":40}]' | jq 'map(select(.age > 25))'
# Saída: [{"age":30},{"age":40}]
map(f) aplica f a cada elemento; select(cond) mantém apenas os elementos em que a condição é verdadeira.
Padrão 7 — Correspondência de prefixo de string
echo '[{"name":"api-gateway"},{"name":"web-ui"},{"name":"api-auth"}]' \
| jq '.[] | select(.name | startswith("api"))'
# Saída: {"name":"api-gateway"}
# {"name":"api-auth"}
Também úteis: endswith("..."), contains("..."), test("^regex$").
Padrão 8 — Condições combinadas
echo '[{"type":"A","count":5},{"type":"A","count":15},{"type":"B","count":20}]' \
| jq '.[] | select(.type == "A" and .count > 10)'
# Saída: {"type":"A","count":15}
and, or, not se comportam como esperado.
Padrão 9 — Remover campos sensíveis
echo '{"user":"alice","password":"s3cret","token":"abc"}' | jq 'del(.password, .token)'
# Saída: {"user":"alice"}
del() aceita vários caminhos e não falha se algum estiver ausente.
Padrão 10 — Deduplicar por campo
echo '[{"id":1,"v":"a"},{"id":2,"v":"b"},{"id":1,"v":"a2"}]' | jq 'unique_by(.id)'
# Saída: [{"id":1,"v":"a"},{"id":2,"v":"b"}]
unique deduplica valores inteiros; unique_by(f) deduplica pelo resultado de um filtro.
Transformar (padrões 11–15)
Padrão 11 — Renomear campos
echo '[{"first_name":"Alice","age":30}]' | jq 'map({name: .first_name, age})'
# Saída: [{"name":"Alice","age":30}]
A forma curta {age} equivale a {age: .age}.
Padrão 12 — Adicionar campo calculado com interpolação de string
echo '[{"first":"Alice","last":"Chen"}]' \
| jq 'map(. + {fullName: "\(.first) \(.last)"})'
# Saída: [{"first":"Alice","last":"Chen","fullName":"Alice Chen"}]
\(expr) avalia expr e interpola o valor na string.
Padrão 13 — Achatar arrays aninhados
echo '[{"tags":["a","b"]},{"tags":["c"]}]' | jq '[.[] | .tags[]]'
# Saída: ["a","b","c"]
echo '[[1,2],[3,[4,5]]]' | jq 'flatten'
# Saída: [1,2,3,4,5]
flatten aceita profundidade opcional: flatten(1) remove apenas um nível.
Padrão 14 — Objeto para array e vice-versa
echo '{"a":1,"b":2}' | jq 'to_entries'
# Saída: [{"key":"a","value":1},{"key":"b","value":2}]
echo '[{"key":"a","value":1},{"key":"b","value":2}]' | jq 'from_entries'
# Saída: {"a":1,"b":2}
Esse par habilita transformações que exigem iterar sobre as chaves de um objeto — algo que a sintaxe de pontos não permite diretamente.
Padrão 15 — Mesclar profundamente dois objetos
echo '{"a":{"x":1},"b":2}' | jq '. * {a:{y:9}, c:3}'
# Saída: {"a":{"x":1,"y":9},"b":2,"c":3}
O operador * faz mesclagem profunda. Para mesclagem superficial use + (o lado direito vence).
Agregar (padrões 16–20)
Padrão 16 — Tamanho de arrays, objetos e strings
echo '[1,2,3,4]' | jq 'length' # 4
echo '{"a":1,"b":2}' | jq 'length' # 2
echo '"hello"' | jq 'length' # 5
Padrão 17 — Somar um campo
echo '[{"price":10},{"price":25},{"price":5}]' | jq '[.[].price] | add'
# Saída: 40
add soma números, concatena strings ou funde arrays — conforme o tipo de entrada.
Padrão 18 — Agrupar por campo
echo '[{"cat":"A","n":1},{"cat":"B","n":2},{"cat":"A","n":3}]' | jq 'group_by(.cat)'
# Saída: [[{"cat":"A","n":1},{"cat":"A","n":3}],[{"cat":"B","n":2}]]
Cada grupo vira um array interno. Combine com map para agregar por grupo.
Padrão 19 — Ordenar decrescente
echo '[{"date":"2026-01-03"},{"date":"2026-01-01"},{"date":"2026-01-02"}]' \
| jq 'sort_by(.date) | reverse'
# Saída: [{"date":"2026-01-03"},{"date":"2026-01-02"},{"date":"2026-01-01"}]
Strings de data ISO 8601 ordenam-se corretamente como strings. Outros formatos exigem parsing antes — o guia do timestamp Unix cobre em detalhe epoch segundos, milissegundos e conversão de fuso horário.
Padrão 20 — Máximo ou mínimo por campo
echo '[{"name":"a","rating":4.1},{"name":"b","rating":4.8},{"name":"c","rating":3.9}]' \
| jq 'max_by(.rating)'
# Saída: {"name":"b","rating":4.8}
min_by, max_by retornam um único elemento. Top N com sort_by(.rating) | reverse | .[:N].
Formatar saída (padrões 21–25)
Padrão 21 — Saída CSV
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' \
| jq -r '.[] | [.name, .age] | @csv'
# Saída: "Alice",30
# "Bob",25
@csv coloca aspas em strings e escapa as internas. -r remove as aspas externas de JSON, deixando o CSV pronto para pipe. Para o ida e volta completo entre CSV e JSON em um pipeline, consulte o guia de conversão CSV para JSON.
Padrão 22 — Saída TSV
echo '[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]' \
| jq -r '.[] | [.id, .name] | @tsv'
# Saída: 1 Alice
# 2 Bob
Saída separada por tabulação conversa bem com cut, awk e column -t.
Padrão 23 — Saída de string crua
echo '["alpha","beta"]' | jq -r '.[]'
# Saída: alpha
# beta
Sem -r, cada linha viria com aspas. Saída crua é o que você passa para xargs, while read ou outro comando de shell.
Padrão 24 — NDJSON / JSON Lines
echo '[{"a":1},{"a":2}]' | jq -c '.[]'
# Saída: {"a":1}
# {"a":2}
Cada linha é um valor JSON autônomo — o formato usado por Kafka, Elasticsearch e a maioria dos loggers estruturados. -c também remove todo espaço interno.
Padrão 25 — Interpolação de string para saída formatada
echo '[{"name":"server-1","cpu":0.73},{"name":"server-2","cpu":0.21}]' \
| jq -r '.[] | "\(.name): \(.cpu * 100)% CPU"'
# Saída: server-1: 73% CPU
# server-2: 21% CPU
Ótimo para resumos e linhas de log onde o JSON cru seria ruído.
DevOps na prática (padrões 26–30)
Padrão 26 — kubectl: nomes de todo pod em execução
kubectl get pods -o json \
| jq -r '.items[] | select(.status.phase=="Running") | .metadata.name'
Pipeline: itera pods, mantém apenas Running, emite o nome como string crua.
Padrão 27 — AWS EC2: IDs de instância com IP público
aws ec2 describe-instances \
| jq -r '.Reservations[].Instances[] | [.InstanceId, .PublicIpAddress // "none"] | @tsv'
O operador alternativo // fornece um fallback quando o campo é null — evita um null literal na coluna de saída.
Padrão 28 — API do GitHub: mesclar resultados paginados
for p in 1 2 3; do
curl -s "https://api.github.com/orgs/myorg/repos?per_page=100&page=$p"
done | jq -s 'add | map(.name)'
-s absorve todas as respostas em um array de arrays, add concatena, map(.name) extrai nomes. Padrão comum para qualquer API paginada.
Padrão 29 — Filtrar arquivos de log estruturados
cat app.log | jq -c 'select(.level=="error")'
Assume que o log está em NDJSON (um objeto JSON por linha). Combine com tail -f para monitoramento ao vivo:
tail -f app.log | jq -c 'select(.level=="error") | {ts: .timestamp, msg: .message}'
Padrão 30 — Docker: todos os nomes de imagem em uso
docker inspect $(docker ps -q) | jq -r '.[].Config.Image' | sort -u
Útil para verificar rapidamente quais versões de imagem estão em execução em um host.
Erros comuns e como resolver
Todo usuário de jq tropeça nestes. Saber a solução com antecedência poupa horas.
Cannot iterate over null (null)
O campo de entrada que você tentou iterar era null ou estava ausente. Dois caminhos:
# Opção A: operador opcional
echo '{}' | jq '.items[]?'
# Saída: (nada, sem erro)
# Opção B: operador alternativo com valor padrão
echo '{}' | jq '(.items // [])[]'
# Saída: (nada, sem erro)
Use ? quando quiser pular silenciosamente. Use // [] quando quiser forçar um array vazio concreto para que os filtros seguintes continuem rodando.
Cannot index array with "key"
Você escreveu .foo, mas o valor atual é um array. Adicione [] para iterar:
# Errado
echo '{"users":[{"name":"Alice"}]}' | jq '.users.name'
# Erro: Cannot index array with "name"
# Certo
echo '{"users":[{"name":"Alice"}]}' | jq '.users[].name'
# Saída: "Alice"
Problemas com aspas no shell
Envolva o programa jq inteiro em aspas simples e use aspas duplas internamente para literais de string:
# Funciona em qualquer lugar
jq '.users[] | select(.role == "admin")'
# Quebra — o shell interpreta as aspas duplas primeiro
jq ".users[] | select(.role == \"admin\")"
Casos extremos no PowerShell do Windows
O PowerShell não trata aspas simples do mesmo jeito. Prefira aspas duplas em volta do programa e escape as internas, ou use here-string:
jq "@'
.users[] | select(.role == \"admin\")
'@"
Para qualquer coisa não trivial, salve o filtro em um arquivo .jq e execute jq -f filter.jq.
Uso indevido de -r
-r só afeta resultados de string. Aplicar em um objeto produz um objeto JSON normal:
echo '{"a":1}' | jq -r '.'
# Saída: {"a":1} ← inalterado; -r não tinha nada para remover
Se você quer um campo específico sem aspas, selecione-o primeiro: jq -r '.a'.
jq rejeita JSON com comentários ou vírgulas finais
echo '{"a": 1, /* nota */ "b": 2,}' | jq .
# parse error: Invalid numeric literal
jq segue estritamente o RFC 8259 JSON — sem comentários, sem vírgulas finais, sem chaves sem aspas. Se o arquivo for JSON5 ou JSONC (comum em arquivos de configuração), remova essas extensões antes de pipear para jq. O guia de formatação JSON5 e JSONC explica quais parsers os suportam e como converter para JSON estrito.
jq vs alternativas: gron, fx, jj, yq
jq não é a única opção, e às vezes outra ferramenta é mais rápida:
| Ferramenta | Ponto forte | Quando puxar |
|---|---|---|
| gron | Achata JSON em caminhos grepáveis | Explorar esquemas desconhecidos — você não sabe onde está a chave |
| fx | Explorador TUI interativo com realce | Folhear JSONs grandes manualmente |
| jj | Bem mais rápido que jq, sintaxe limitada | Loops quentes processando milhões de registros |
| yq | Mesma linguagem de filtro mas para YAML | Manifestos do Kubernetes e configuração de CI |
| JSON Formatter no navegador | Realce de sintaxe, mensagens precisas, sem instalação | Depurar uma resposta única durante o desenvolvimento |
Para trabalho diário em shell, jq ganha na composabilidade. Para exploração ocasional, gron costuma ser mais rápido. Para YAML, use yq — não tente yq seguido de jq.
Dicas pro para o dia a dia
Alguns hábitos que fazem o jq parecer natural:
-
Mantenha um
.jqrcem$HOME. Deixe funções auxiliares lá, e elas ficam disponíveis em toda chamada dejq:def running: select(.status.phase == "Running"); def table(f): [f] | @tsv; -
Use o jqplay.org para filtros complexos. Cole o JSON à esquerda, itere o filtro à direita, jogue a versão que funciona no script.
-
Monte seu próprio cheat sheet a partir do
history.history | grep 'jq ' | sort -u > ~/jq-patterns.txtcaptura todo padrão que você realmente usou. -
Combine com o JSON Formatter do navegador para esquemas desconhecidos. Explore a estrutura visualmente primeiro para descobrir o caminho necessário, depois escreva o comando
jq. -
Monitorar valores ao vivo:
watch -n 5 "curl -s api.example.com/health | jq '.uptime'"atualiza a cada 5 segundos — um mini dashboard de ops sem dependências.
FAQ
O que é jq e por que desenvolvedores usam?
jq é um processador JSON de linha de comando. Extrai, filtra e transforma JSON em pipelines de shell sem script Python ou Node — o caminho mais curto entre respostas de API, arquivos de log ou saída do kubectl e o campo que você quer.
O jq está disponível no Windows?
Está. Instale com winget install jqlang.jq, Chocolatey choco install jq ou baixe o binário em jqlang.org. As regras de aspas do PowerShell diferem das do bash — na dúvida, salve os filtros em um arquivo .jq e execute jq -f filter.jq.
Em que o jq se diferencia de um formatador JSON de navegador?
Um JSON Formatter de navegador é interativo — você cola JSON, vê realce e erros, copia. jq é não interativo — descreve a transformação uma vez, roda em um pipeline de shell. Use o navegador para depurar uma resposta; use jq para automatizar em centenas de entradas.
Por que o jq diz «Cannot iterate over null»?
Você tentou iterar (.[]) sobre um valor null — normalmente porque o campo faltou na entrada. Corrija com o operador opcional .items[]? ou forneça um padrão com .items // [] | .[].
O jq pode alterar arquivos no lugar?
Não diretamente — o jq escreve em stdout. Use um arquivo temporário ou o sponge do moreutils: jq '.version = "2.0"' config.json | sponge config.json. Faça backup do original antes; um filtro escrito errado sobrescreve o arquivo.
Como uso jq com respostas de curl?
Direcione curl -s para jq. A flag -s silencia a barra de progresso do curl para que só o corpo JSON chegue ao jq:
curl -s https://api.github.com/users/octocat | jq '.name, .blog'
Qual a diferença entre o | do jq e o | do shell?
O pipe do shell passa bytes entre processos. O pipe do jq passa valores JSON entre filtros em uma única invocação. Um comando com vários pipes internos roda em um processo — mais barato que encadear jq | jq | jq.
O jq lida com JSON Lines (NDJSON)?
Sim, nativamente. O jq lê cada linha como um valor JSON independente quando elas estão separadas por espaços. Use -c para emitir NDJSON e -s para coletar NDJSON em um único array.
Como formato JSON sem filtrar nada?
Use o filtro identidade: cat data.json | jq . ou jq . < data.json. Ele analisa, valida e formata com indentação de dois espaços — sem filtro.
Existe alternativa ao jq com interface gráfica?
Existe. O fx oferece uma TUI interativa. Para uma GUI sem instalação, o JSON Formatter baseado em navegador atende a maioria das necessidades de explorar e validar. Ferramentas web como jqplay.org oferecem o próprio jq com prévia ao vivo.
Quando usar jq em vez de escrever um script Python?
Escolha jq quando a tarefa for pontual, couber em um pipeline de shell e permanecer na semântica de filtrar/transformar/extrair. Mude para Python se precisar de testes unitários, estado complexo, bibliotecas de terceiros, ou lógica que exceda a legibilidade de um arquivo .jq.
Como uso expressões regulares no jq?
O jq expõe regex via test("pattern"), match("pattern"), capture("pattern") e scan("pattern"), todos em sintaxe PCRE. Passe flags como segundo argumento: test("abc"; "i") para ignorar maiúsculas/minúsculas. match devolve offsets e capturas; scan emite cada correspondência não sobreposta.
Como preservar caracteres acentuados (ç, ã, é) na saída de jq?
jq emite UTF-8 por padrão e mantém acentos desde que você não use -a / --ascii-output. Se aparecer \u00e7 em vez de ç, geralmente é o locale do terminal: confirme que $LANG é pt_BR.UTF-8 ou en_US.UTF-8 e evite a flag -a.
Pontos-chave
- Primeiro o modelo mental: um filtro entra, zero ou mais valores JSON saem, composição com
|. O resto é sintaxe. - Aprenda por tarefa, não por operador: os 30 padrões cobrem cerca de 95 % do uso diário do
jq. - Trate null explicitamente:
?para pular em silêncio,// defaultpara fallback concreto. A maioria das correções deCannot iterate over nullpassa por um desses dois. - Saiba quando
jqé a ferramenta errada: respostas únicas pertencem a um JSON Formatter de navegador; YAML pertence aoyq; lógica complexa pertence a código real. - Combine com sua stack existente:
jqbrilha dentro decurl,kubectl,aws,dockere pipelines de log. Use como cola, não como camada de lógica.
Para fluxos JSON relacionados, veja o guia de formatação JSON5 e JSONC sobre extensões de sintaxe para arquivos de configuração, e o guia de conversão CSV para JSON para migrações de formato onde o jq se encaixa no pipeline. Quando seu JSON tem timestamps, o guia do timestamp Unix cobre as armadilhas ao transformar campos de data.