Como usar jq para processar JSON no terminal

1. Introdução ao jq e sua importância no terminal

jq é um processador JSON leve, flexível e extremamente poderoso para linha de comando. Ele funciona como um "sed para JSON", permitindo filtrar, transformar, agregar e formatar dados JSON de forma declarativa. Sua importância no ecossistema de desenvolvimento moderno é inegável: APIs REST retornam JSON, arquivos de configuração (Docker Compose, Kubernetes) são JSON, logs estruturados seguem esse formato, e ferramentas como curl frequentemente produzem saídas JSON.

Sem jq, manipular JSON no terminal seria um pesadelo de grep, awk e expressões regulares frágeis. Com jq, você escreve filtros concisos e previsíveis.

Instalação rápida:
- Linux (Debian/Ubuntu): sudo apt install jq
- macOS: brew install jq
- Windows: choco install jq ou baixar o binário do site oficial

Verifique a instalação com:

jq --version

Saída esperada: jq-1.7.1 (ou versão similar).

2. Estrutura básica e primeiros comandos

A sintaxe fundamental do jq é:

jq 'filtro' arquivo.json

Ou em pipeline com curl:

curl https://api.example.com/dados | jq '.'

O filtro mais básico é . (ponto), que retorna o JSON inteiro formatado (pretty-print). Sem jq, a saída de curl vem em linha única.

Considere o arquivo pessoa.json:

{"nome": "Ana", "idade": 30, "endereco": {"cidade": "São Paulo", "uf": "SP"}}

Acessando chaves simples:

jq '.nome' pessoa.json

Saída:

"Ana"

Navegação aninhada:

jq '.endereco.cidade' pessoa.json

Saída:

"São Paulo"

O operador | (pipe) permite encadear filtros, similar ao shell:

jq '.endereco | .uf' pessoa.json

3. Filtros de seleção e iteração

Arrays são comuns em JSON. O operador .[] desempacota todos os elementos de um array.

Arquivo usuarios.json:

[
  {"nome": "Carlos", "idade": 25},
  {"nome": "Maria", "idade": 32},
  {"nome": "João", "idade": 28}
]

Desempacotar array:

jq '.[]' usuarios.json

Saída (três objetos separados):

{
  "nome": "Carlos",
  "idade": 25
}
{
  "nome": "Maria",
  "idade": 32
}
{
  "nome": "João",
  "idade": 28
}

Acessar índice específico:

jq '.[0]' usuarios.json

Saída: o primeiro objeto.

Slicing (fatia):

jq '.[1:3]' usuarios.json

Retorna os elementos dos índices 1 e 2 (exclui o 3).

Extrair campos de objetos:

jq '.[] | .nome' usuarios.json

Saída:

"Carlos"
"Maria"
"João"

4. Filtragem condicional com select

O filtro select(condição) mantém apenas objetos que satisfazem a condição.

Filtrar por valor exato:

jq '.[] | select(.idade > 30)' usuarios.json

Saída:

{
  "nome": "Maria",
  "idade": 32
}

Operadores lógicos:

jq '.[] | select(.idade > 25 and .nome != "Maria")' usuarios.json

Saída:

{
  "nome": "João",
  "idade": 28
}

Exemplo prático: filtrar usuários ativos em um log JSON:

jq '.[] | select(.status == "ativo")' logs.json

5. Transformação e construção de novos JSON

jq permite criar novos objetos a partir de dados existentes.

Criar objeto simples:

jq '.[] | {nome_completo: .nome, faixa_etaria: if .idade < 30 then "jovem" else "adulto" end}' usuarios.json

Saída:

{
  "nome_completo": "Carlos",
  "faixa_etaria": "jovem"
}
{
  "nome_completo": "Maria",
  "faixa_etaria": "adulto"
}
{
  "nome_completo": "João",
  "faixa_etaria": "jovem"
}

Adicionar chave:

jq '.[] | . += {"ativo": true}' usuarios.json

Remover chave:

jq '.[] | del(.idade)' usuarios.json

6. Agregação e cálculos com jq

Funções de redução permitem sumarizar dados.

Comprimento de array:

jq 'length' usuarios.json

Saída: 3

Somar valores numéricos:

jq '[.[] | .idade] | add' usuarios.json

Saída: 85

Agrupamento (group_by):

Arquivo vendas.json:

[
  {"produto": "caneta", "quantidade": 10},
  {"produto": "lapis", "quantidade": 5},
  {"produto": "caneta", "quantidade": 7}
]
jq 'group_by(.produto) | map({produto: .[0].produto, total: map(.quantidade) | add})' vendas.json

Saída:

[
  {
    "produto": "caneta",
    "total": 17
  },
  {
    "produto": "lapis",
    "total": 5
  }
]

Estatísticas simples:

jq '[.[] | .idade] | min, max, unique' usuarios.json

7. Integração com outras ferramentas do terminal

Combinando com curl:

curl -s https://jsonplaceholder.typicode.com/users | jq '.[] | {nome: .name, email: .email}'

Usando em scripts shell:

for usuario in $(curl -s api.com/usuarios | jq -r '.[].nome'); do
  echo "Processando: $usuario"
done

A flag -r (raw) remove as aspas das strings, permitindo uso direto no shell.

Saída compacta com -c:

jq -c '.[] | {nome, idade}' usuarios.json

Útil para logs de uma linha.

8. Boas práticas e dicas avançadas

Tratamento de erros com try e catch:

jq 'try .[].inexistente catch "campo_ausente"' dados.json

Uso de variáveis com --arg:

jq --arg nome "Maria" '.[] | select(.nome == $nome)' usuarios.json

Isso permite filtros dinâmicos sem concatenação de strings no filtro.

Monitoramento de logs JSON em tempo real:

tail -f app.log | jq 'select(.level == "ERROR") | {timestamp: .time, mensagem: .message}'

Boas práticas:
- Sempre coloque filtros entre aspas simples para evitar expansão do shell.
- Use -r quando precisar de saída sem aspas para pipelines.
- Teste filtros com jq interativamente antes de incorporar em scripts.
- Prefira jq a grep/awk para JSON: é semanticamente correto.

jq é uma ferramenta indispensável no cinto de utilidades de qualquer profissional que lida com dados estruturados no terminal. Domine seus filtros e você manipulará JSON com a mesma fluência que manipula texto com sed e awk.

Referências