0Pricing
DevOps Bootcamp · Aula

Filtragem e seleção de JSON com pipelines do jq

Navegue por objetos e matrizes aninhados usando seletores, pipes e o filtro select do jq.

Filtragem e seleção de JSON com pipelines do jq é uma aula grátis de DevOps Bootcamp no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de DevOps Bootcamp, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de DevOps Bootcamp inclui 4 aulas no total.

O que é jq e por que usá-lo?

jq é uma ferramenta de linha de comando leve e poderosa para analisar, filtrar e transformar dados JSON. Ele é o sed do JSON — você envia JSON para ele por um fluxo e recebe uma saída estruturada.

  • Já vem instalado na maioria das distribuições Linux ou está disponível por meio de apt install jq / brew install jq
  • Funciona perfeitamente em fluxos do shell com curl, cat e outras ferramentas
  • Oferece suporte a filtragem, mapeamento, redução e conversão de formato

A chamada básica é: jq '<filter>' file.json ou por fluxo, como em cat file.json | jq '<filter>'. O filtro . (ponto) é a identidade — ele formata de maneira legível todo o documento.

# Pretty-print a JSON file
jq '.' data.json

# Or pipe from curl
curl -s https://api.github.com/users/torvalds | jq '.'

Selecionando campos de objetos com notação de ponto

Para acessar um campo em um objeto JSON, use a notação de ponto: .fieldName. Você pode encadear seletores para navegar por objetos aninhados.

  • .name — campo de nível superior
  • .address.city — campo aninhado
  • ."field-with-dash" — campos com caracteres especiais precisam de aspas

Se o campo não existir, jq retornará null em vez de produzir um erro. Isso torna seu uso seguro em scripts, sem verificações adicionais de nulo para campos opcionais.

# Given: {"name":"Alice","address":{"city":"Berlin","zip":"10115"}}
echo '{"name":"Alice","address":{"city":"Berlin","zip":"10115"}}' | jq '.name'
# Output: "Alice"

echo '{"name":"Alice","address":{"city":"Berlin","zip":"10115"}}' | jq '.address.city'
# Output: "Berlin"

Acessando elementos de matrizes e iterando

As matrizes JSON são acessadas com a notação de colchetes. jq usa índices começando em zero.

  • .items[0] — primeiro elemento
  • .items[-1] — último elemento
  • .items[1:3] — fatia (do índice 1 até, mas sem incluir, o 3)
  • .items[] — desmembrar a matriz: gera cada elemento como um valor separado (este é o iterador)

O iterador [] é fundamental para os fluxos do jq — ele permite aplicar filtros posteriores a cada elemento de maneira independente.

# Given an array of users
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Carol"}]' | jq '.[0]'
# Output: {"name":"Alice"}

# Iterate all elements and extract .name from each
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Carol"}]' | jq '.[].name'
# Output:
# "Alice"
# "Bob"
# "Carol"

Criando fluxos jq com o operador de canalização

Assim como o canal do shell |, jq tem seu próprio operador interno de canalização. Ele passa a saída de um filtro como entrada para o próximo.

  • jq '.users[] | .name' — itera pelos usuários e depois extrai o nome de cada um
  • jq '.data | .items[] | .id' — navega até os dados, desmembra os itens e extrai o identificador

Os canais dentro de uma expressão jq permitem criar transformações complexas passo a passo. Cada estágio recebe o que o estágio anterior produziu — inclusive vários valores vindos de um iterador.

Ideia principal: quando um iterador produz N valores, cada filtro posterior é executado N vezes, uma vez para cada valor.

# Nested pipeline: navigate -> iterate -> extract
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
  | jq '.users[] | .name'
# Output:
# "Alice"
# "Bob"

# Chain more stages
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
  | jq '.users[] | .age'
# Output:
# 30
# 25

Filtrando com select()

O filtro select(condition) deixa um valor passar somente se a condição for verdadeira; caso contrário, não produz saída. Ele é o equivalente, no jq, a grep ou WHERE em SQL.

  • select(.age > 18) — mantém os objetos em que a idade é maior que 18
  • select(.status == "active") — verifica a igualdade
  • select(.name | startswith("A")) — teste de texto aninhado

Combine select com o iterador para filtrar matrizes: .items[] | select(.active) gera somente os elementos em que .active é verdadeiro.

# Filter array elements by a condition
echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":25}]' \
  | jq '.[] | select(.age >= 18) | .name'
# Output:
# "Alice"
# "Carol"

# Filter by string equality
echo '[{"name":"Alice","role":"admin"},{"name":"Bob","role":"user"}]' \
  | jq '.[] | select(.role == "admin") | .name'
# Output: "Alice"

Reconstruindo objetos e matrizes com {} e []

jq permite remodelar dados construindo novos objetos com {} e novas matrizes com [].

  • {name: .name, city: .address.city} — seleciona e renomeia campos em um novo objeto
  • [.items[] | .id] — reúne os valores iterados novamente em uma matriz
  • Forma abreviada: {name, age} equivale a {name: .name, age: .age}

Envolver um fluxo em [...] é chamado de construção de matriz e é essencial quando você quer uma matriz JSON como saída, em vez de um fluxo de valores.

# Reshape: keep only selected fields
echo '[{"id":1,"name":"Alice","password":"secret"},{"id":2,"name":"Bob","password":"secret"}]' \
  | jq '[.[] | {id, name}]'
# Output:
# [
#   {"id": 1, "name": "Alice"},
#   {"id": 2, "name": "Bob"}
# ]

# Collect filtered names into an array
echo '[{"name":"Alice","active":true},{"name":"Bob","active":false}]' \
  | jq '[.[] | select(.active) | .name]'
# Output: ["Alice"]

Trabalhando com matrizes aninhadas e descida recursiva

JSON do mundo real geralmente é profundamente aninhado. jq oferece duas ferramentas para navegação profunda:

  • .a.b.c — caminho explícito quando a estrutura é conhecida
  • .. | .fieldName? — descida recursiva: percorre cada nó da árvore e gera os valores nos locais em que a chave existe

O operador ? (tentativa) suprime erros quando um campo não existe em determinado nó, o que é essencial ao usar descida recursiva em árvores heterogêneas.

Use a descida recursiva com moderação em documentos grandes — ela visita cada nó e pode ser lenta. Prefira caminhos explícitos quando a estrutura for previsível.

# Explicit deep path
echo '{"a":{"b":{"c":42}}}' | jq '.a.b.c'
# Output: 42

# Recursive descent: find all "id" values anywhere in the tree
echo '{"users":[{"id":1,"profile":{"id":99}},{"id":2}]}' \
  | jq '.. | .id?'
# Output:
# 1
# 99
# 2

Exemplo prático: analisando respostas de API com curl

Um dos casos de uso mais comuns do jq é analisar respostas de APIs REST obtidas com curl. Combinar curl -s (silencioso) com um fluxo jq fornece uma extração de dados limpa e adequada para scripts.

  • Extrair um único valor: curl -s URL | jq '.field'
  • Criar uma tabela-resumo: iterar por uma matriz e reconstruir objetos apenas com os campos necessários
  • Usar -r (saída bruta) para remover as aspas ao redor dos valores de texto — essencial ao atribuí-los a variáveis do shell

Dica: sempre adicione -r quando a saída do jq for usada como variável do shell ou canalizada para outro comando.

#!/usr/bin/env bash
# Fetch GitHub repo info and extract specific fields
REPO="torvalds/linux"
RESPONSE=$(curl -s "https://api.github.com/repos/${REPO}")

# Extract fields
STARS=$(echo "$RESPONSE" | jq -r '.stargazers_count')
LANG=$(echo  "$RESPONSE" | jq -r '.language')
DESC=$(echo  "$RESPONSE" | jq -r '.description')

echo "Stars : $STARS"
echo "Lang  : $LANG"
echo "Desc  : $DESC"

Usando map() e map_values()

jq oferece duas funções convenientes de ordem superior para transformar coleções:

  • map(f) — aplica o filtro f a cada elemento de uma matriz, retornando uma nova matriz. Equivale a [.[] | f].
  • map_values(f) — aplica f a cada valor de um objeto ou matriz, preservando as chaves/índices.

Essas funções são mais legíveis do que envolver manualmente os fluxos em [] e representam o estilo idiomático do jq para transformações que devem continuar sendo matrizes.

# map: extract a field from each element
echo '[{"name":"Alice","score":95},{"name":"Bob","score":80}]' \
  | jq 'map(.name)'
# Output: ["Alice", "Bob"]

# map with select: filter + transform in one step
echo '[{"name":"Alice","score":95},{"name":"Bob","score":60}]' \
  | jq 'map(select(.score >= 70) | .name)'
# Output: ["Alice"]

# map_values: multiply every value in an object by 2
echo '{"a":1,"b":2,"c":3}' | jq 'map_values(. * 2)'
# Output: {"a":2,"b":4,"c":6}

Lidando com campos opcionais e valores padrão com //

Dados JSON de fontes externas geralmente são inconsistentes — campos podem estar ausentes ou nulos. jq oferece o operador alternativo // (barra dupla) para fornecer um valor padrão.

  • .nickname // "anonymous" — usa .nickname se ele não for nulo/falso; caso contrário, usa "anonymous"
  • .count // 0 — valor padrão numérico
  • Combine com select: select((.status // "inactive") == "active")

Isso é muito mais conciso do que o equivalente no shell, ${VAR:-default}, e pode ser combinado facilmente dentro de fluxos mais longos.

# Provide defaults for missing/null fields
echo '[{"name":"Alice","role":"admin"},{"name":"Bob"}]' \
  | jq '[.[] | {name, role: (.role // "user")}]'
# Output:
# [
#   {"name": "Alice", "role": "admin"},
#   {"name": "Bob",   "role": "user"}
# ]

# Numeric default
echo '{"items":[1,2,3]}' | jq '.total // 0'
# Output: 0

Script prático: analisador de registros JSON

O registro estruturado em JSON é padrão nos sistemas modernos. Veja um script realista que lê um arquivo de registro JSON delimitado por quebras de linha, filtra as entradas de erro e formata um resumo legível.

Principais padrões utilizados:

  • -c (saída compacta) — um objeto JSON por linha, útil para canalizar para laços do shell
  • --arg name value — injeta uma variável do shell como argumento de texto do jq
  • select para filtragem por nível de registro
  • -r para saída de texto bruto adequada para echo
#!/usr/bin/env bash
# Parse newline-delimited JSON logs and report ERRORs
# Each log line: {"level":"ERROR","msg":"...","ts":"2024-01-15T10:23:00Z","svc":"auth"}

LOG_FILE="/var/log/app/app.log"
LEVEL="ERROR"

echo "=== $LEVEL entries in $LOG_FILE ==="

jq -r --arg lvl "$LEVEL" \
  'select(.level == $lvl) | "[\(.ts)] [\(.svc)] \(.msg)"' \
  "$LOG_FILE"

# Count errors per service
echo ""
echo "=== Error count by service ==="
jq -r --arg lvl "$LEVEL" \
  'select(.level == $lvl) | .svc' "$LOG_FILE" \
  | sort | uniq -c | sort -rn

Verificação de conhecimento: comportamento de select() no jq

Teste sua compreensão de como select() funciona dentro de um fluxo do jq.

Considere o seguinte comando:

echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":22}]' | jq '[.[] | select(.age >= 18) | .name]'

Qual será o resultado?

Recapitulação da lição: fluxos do jq para filtrar JSON

Você aprendeu os principais recursos do jq para navegar e filtrar JSON na linha de comando:

  • Notação de ponto (.field, .a.b.c) seleciona campos de objetos
  • Acesso a matrizes (.[0], .[]) indexa e percorre matrizes
  • Operador de pipe (|) encadeia filtros; cada etapa processa todos os valores da etapa anterior
  • select(cond) filtra valores, mantendo apenas aqueles em que a condição é verdadeira
  • Construção de objetos/matrizes ({}, [], map()) reorganiza os dados em novas estruturas
  • Operador alternativo (//) fornece valores padrão para campos nulos ou ausentes
  • Opção -r remove as aspas para atribuição a variáveis do shell; --arg injeta variáveis do shell com segurança
  • Descida recursiva (.. | .field?) pesquisa árvores profundamente aninhadas quando o caminho é desconhecido

Com esses blocos básicos, você pode transformar qualquer resposta de uma API JSON, arquivo de registro ou configuração exatamente nos dados de que seus scripts precisam — tudo sem sair do terminal.

Perguntas Frequentes

A aula “Filtragem e seleção de JSON com pipelines do jq” é grátis?

Sim — o texto completo de “Filtragem e seleção de JSON com pipelines do jq” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de DevOps Bootcamp, atualize para CoddyKit PRO. O curso de DevOps Bootcamp inclui 4 aulas no total.

O que vou aprender em “Filtragem e seleção de JSON com pipelines do jq”?

Navegue por objetos e matrizes aninhados usando seletores, pipes e o filtro select do jq. Você pratica DevOps Bootcamp com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar DevOps Bootcamp?

Nenhuma experiência prévia é necessária. DevOps Bootcamp no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Filtragem e seleção de JSON com pipelines do jq”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de DevOps Bootcamp?

Sim. Cada aula de DevOps Bootcamp inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Filtragem e seleção de JSON com pipelines do jq
  2. Transformação e criação de objetos JSON com jq
  3. Consumo conjunto de APIs REST com curl e jq
  4. Edição de arquivos de configuração YAML com yq
← Voltar para DevOps Bootcamp