Basico do jq: Como Processar JSON no Shell
O Que Voce Vai Aprender
- Como formatar JSON de
curlou respostas de API em formato legivel - O vocabulario essencial do jq que voce realmente precisa:
select,map,-re mais - Padroes seguros que evitam as armadilhas comuns: aspas perdidas vazando em variaveis do shell, propagacao de null e escritas de arquivo quebradas
Referencia Rapida (padroes de producao)
- Apenas formatar ->
jq . - Extrair um valor ->
jq -r '.field' - Explodir um array em um JSON por linha ->
jq -c '.[]' - Filtrar por condicao ->
jq '.[] | select(.status=="ok")' - Evitar propagacao de
null->jq '.field // empty'
Ambiente Assumido
- jq 1.6 ou posterior (Ubuntu 20.04+
apt install jqe suficiente; diferencas da 1.7 indicadas inline) - Referencia oficial: jq Manual
O Que e o jq?
jq e uma linguagem de filtro e ferramenta de linha de comando com reconhecimento de JSON. Diferente de forcar grep/awk em JSON, jq entende a estrutura, o que significa menos desastres com regex em pipelines de API, agregacao de logs e scripts de CI.
- Segue o modelo de pipe Unix: stdin -> filtro -> stdout
- Expressoes de filtro sao avaliadas da esquerda para a direita, assim como pipes do shell
- Tem um sistema de tipos real: numeros, strings, arrays, objetos,
nulle booleanos
Como Instalar o jq?
O caminho mais rapido e o gerenciador de pacotes do seu sistema. Se voce usar jq em scripts de CI, fixe a versao com jq --version porque o comportamento difere entre releases principais.
# Ubuntu / Debian $ sudo apt update && sudo apt install jq # RHEL / Rocky / AlmaLinux $ sudo dnf install jq # macOS (Homebrew) $ brew install jq # Verificar $ jq --version
Em CentOS 7 mais antigo, voce precisa do epel-release primeiro. Para runners de CI, o binario estatico unico da pagina oficial de releases colocado em /usr/local/bin/jq e a opcao mais portavel.
Como Ler um Filtro Basico?
Um filtro jq e uma transformacao aplicada a sua entrada. O filtro vazio . e a identidade (formata e retorna). Use .field para ler uma chave de objeto e .[] para explodir um array.
1. Formatacao
$ echo '{"name":"linny","age":3}' | jq .{
"name": "linny",
"age": 3
}
2. Extrair uma chave
$ echo '{"name":"linny","age":3}' | jq '.name'"linny"
3. Iterar sobre um array
$ echo '[{"id":1},{"id":2}]' | jq '.[]'{"id":1}
{"id":2}
Sempre envolva filtros em aspas simples. Aspas duplas deixam o shell interpretar $ e crases, o que corrompe sua expressao jq. '...' e a regra.
Como Trabalhar com Objetos e Arrays?
Combine .[] (explodir array), , (avaliacao paralela) e | (encadear filtros). Parece exatamente com grep | awk.
Extrair um campo de cada elemento
$ echo '[{"id":1,"tag":"a"},{"id":2,"tag":"b"}]' \
| jq '.[].tag'"a" "b"
Construir uma tupla de campos selecionados
$ echo '[{"id":1,"tag":"a"},{"id":2,"tag":"b"}]' \
| jq '.[] | {id, tag}'{"id":1,"tag":"a"}
{"id":2,"tag":"b"}
{id, tag} e abreviacao para {id: .id, tag: .tag}. Funciona apenas para chaves de identificador simples.
Descer com seguranca em campos aninhados
$ echo '{"a":{"b":{"c":42}}}' | jq '.a.b.c'
42
# Chaves ausentes produzem null; o ? suprime erros de iteracao
$ echo '{}' | jq '.a.b?.c?'
nullComo Filtrar com select?
select(condition) passa adiante apenas valores onde a condicao e verdadeira. O padrao e explodir um array com .[] primeiro, depois encadear com select. Pense em SQL WHERE.
Filtro de igualdade
$ echo '[{"s":"ok"},{"s":"ng"},{"s":"ok"}]' \
| jq '.[] | select(.s=="ok")'{"s":"ok"}
{"s":"ok"}
Condicoes numericas e compostas
$ jq '.[] | select(.score >= 80 and .active)'
$ jq '.[] | select(.tag=="a" or .tag=="b")'
$ jq '.[] | select(.tag | startswith("v1"))'Verificar a presenca de uma chave
$ echo '[{"a":1},{"b":2}]' \
| jq '.[] | select(has("a"))'{"a":1}
O padrao "filtrar depois extrair"
jq '.[] | select(.status=="error") | .message'
Mantenha a ordem: explodir -> filtrar -> extrair. E mais facil depurar passo a passo. Adicione // empty se quiser pular nulls silenciosamente.
O Que map, length e keys Fazem?
map(f) aplica f a cada elemento de um array, length retorna o tamanho e keys lista as chaves de um objeto. Estas sao as operacoes em massa para trabalhar em um array como um todo.
map: transformar um array
$ echo '[1,2,3]' | jq 'map(. * 10)'
[ 10, 20, 30 ]
map(f) e equivalente a [.[] | f]. A diferenca: .[] | f transmite um elemento por vez, enquanto map(f) retorna o array intacto.
length: contar elementos
$ echo '[{"id":1},{"id":2},{"id":3}]' | jq 'length'
3Para strings retorna a contagem de caracteres, para objetos o numero de chaves, para null retorna 0. Sensivel ao tipo.
keys: listar as chaves
$ echo '{"a":1,"c":3,"b":2}' | jq 'keys'[ "a", "b", "c" ]
keys e ordenado, keys_unsorted preserva a ordem de insercao. Use keys quando precisar de saida deterministica para testes.
Como Formatar a Saida? (-r / -c)
jq . e para humanos, -r (raw) e para variaveis do shell, e -c (compacto) e para encadear com ferramentas orientadas a linhas. Oito em cada dez bugs de jq vem de escolher o modo de saida errado.
-r: remover aspas da string para saida raw
$ echo '{"name":"linny"}' | jq '.name'
"linny"
$ echo '{"name":"linny"}' | jq -r '.name'
linnyQuando voce atribui a uma variavel do shell com NAME=$(...), sempre use -r. Caso contrario, o literal "linny" (com aspas) vai para a variavel.
-c: um JSON por linha
$ echo '[{"id":1},{"id":2}]' | jq -c '.[]'{"id":1}
{"id":2}
Combine -c com loops while read line ou xargs -I {}. E a ponte entre ferramentas JSON e ferramentas Unix tradicionais.
Saida TSV / CSV (@tsv / @csv)
$ echo '[{"id":1,"name":"a"},{"id":2,"name":"b"}]' \
| jq -r '.[] | [.id, .name] | @tsv'1 a 2 b
@csv coloca aspas em valores string; @tsv usa separadores de tabulacao. Empacote valores em um array primeiro, depois encadeie para o formatador.
-r so remove aspas de strings. Numeros e objetos ainda saem como JSON. Para transformar um array em linhas, voce deve explodi-lo com .[] primeiro.
Padroes Praticos para o Trabalho Diario
Formatacao de respostas de API, agregacao de logs e atualizacao de arquivos de configuracao: tres padroes que voce vai reutilizar para sempre. Memorize os templates e adapte.
Buscar com curl e extrair campos especificos
$ curl -sS "https://api.example.com/users" \ | jq -r '.users[] | "\(.id)\t\(.name)"'
-sS significa silencioso em sucesso, barulhento em erro. A interpolacao de string "\(.id)\t\(.name)" permite escolher qualquer separador.
Agregar com group_by
$ jq '[.[] | {status}] | group_by(.status) | map({status: .[0].status, count: length})'group_by(f) retorna um array de arrays agrupados por f. Envolva com map({key: ..., count: length}) para produzir uma tabela de contagem.
Reescrever parte de um arquivo de configuracao
# Atualizar versao em package.json $ jq '.version = "1.2.3"' package.json > package.json.tmp \ && mv package.json.tmp package.json
jq ... file > file esvazia o arquivo. O shell abre > antes do jq ler, truncando-o. Sempre passe por um arquivo temporario, ou use sponge do moreutils.
# Alternativa mais segura com sponge $ jq '.version = "1.2.3"' package.json | sponge package.json
Adicionar a um array
$ echo '{"items":[1,2]}' | jq '.items += [3]'{
"items": [
1,
2,
3
]
}
|= e reatribuicao, += e adicionar e atribuir. Combine com caminhos profundos: .items |= map(. * 2).
Quais Sao as Armadilhas Comuns?
Tres armadilhas pegam quase todo mundo: propagacao de null, erros de tipo e passar valores do shell para filtros. Ler a mensagem de erro antes de pesquisar corta o tempo de depuracao pela metade.
1. Cannot iterate over null
# .users esta ausente
$ echo '{}' | jq '.users[]'
jq: error (at <stdin>:1): Cannot iterate over null (null)Solucao: fornecer um padrao com // [].
$ echo '{}' | jq '.users // [] | .[]'
# (sem saida, exit 0)2. Incorporar variaveis do shell em um filtro
# Ruim: aspas colidem $ KEY="name" $ jq ".$KEY" file.json # apos expansao do shell vira '."name"' em alguns shells # Bom: passe via --arg $ jq --arg key "$KEY" '.[$key]' file.json
--arg passa o valor como uma string; --argjson passa como JSON. Use --argjson para numeros, arrays ou booleanos.
3. "Parece um array mas .[] falha"
$ echo '"abc"' | jq '.[]'
jq: error (at <stdin>:1): Cannot iterate over string ("abc")Uma string nao e um array. Use o filtro type para confirmar o que voce realmente tem.
$ echo '"abc"' | jq 'type' "string"
4. Controlar um script com o codigo de saida
jq -e retorna codigo de saida 1 quando a saida e false ou null, permitindo encadear com || para fluxo de controle.
$ echo '{"ok":false}' | jq -e '.ok' || echo "falhou"
false
falhouTemplates copiar e colar
# Formatar e paginar
jq . file.json | less
# Capturar em uma variavel (sempre use -r)
NAME=$(curl -sS "$URL" | jq -r '.name')
# Transmitir elementos de array como JSON de 1 linha para xargs
curl -sS "$URL" | jq -c '.users[]' \
| xargs -I {} sh -c 'echo "USER: {}"'
# Extracao null-safe com padrao
jq -r '.path.to.value // "DEFAULT"'