JQ - Instalação e Explicação
Compartilho como instalei o JQ e fiz uma explicação inicial que possibilitará você a começar a usar essa excelente ferramenta
Table of contents
Introdução
JSON
é um formato de dados estruturado amplamente utilizado na maioria das APIs e serviços modernos para compartilhar dados. É particularmente popular em aplicativos da web devido à sua natureza leve e compatibilidade como seu próprio nome sugere, o JavaScript
.
Infelizmente terminais de comando como o bash
não podem interpretar e trabalhar com json
diretamente. Isso significa que trabalhar com json
por meio da linha de comando pode ser complicado, vejamos por exemplo uma chamada para a API do filme Star Wars:
curl https://swapi.dev/api/people
E obtemos uma resposta em json
com informações sobre os personagens do filme:
Bom, podemos ver que o json
retornado não é muito amigável para nossa leitura, mas não se preocupe porque há uma forma simples e fácil de resolver isso, e o nome da solução se chama jq
que acabará se tornando uma das suas ferramentas favoritas!
2- Veja como o mesmo request
ficaria usando o jq
:
curl https://swapi.dev/api/people | jq '.'
Instalação
1- Abra seu terminal e digite o comando:
sudo apt install jq
2- Verifique a instalação com o comando:
jq --version
Como usar o JQ
JQ
é mais do que apenas "embelezar" o json em seu bash, ele foi construído em torno do conceito de filtros, como veremos abaixo e existem muitos filtros que podemos usar e combinar sem esforços usando o caractere "pipe
" |
para manipular os dados do json.
Então vamos começar pelo filtro mais simples de todos, que também será o que você acabará usando com mais frequência:
curl https://swapi.dev/api/people | jq '.'
Vamos entender o que aconteceu aqui:
Adicionamos ao final do nosso comando
| jq '.'
Esse
'.'
é um filtro que estamos dizendo ao jq"hey, pegue todos os dados e imprima em um formato json visualmente mais bonito para mim"
.
Avançando...
Ok, já conseguimos ver o json melhor agora, mas imagino que você deve estar se perguntando nesse momento "Certo, é só isso? Mas como que eu pego apenas o nome de um personagem por exemplo?".
Se você se questionou sobre isso, estamos no caminho certo aqui. Vamos detalhar como podemos filtrar apenas o nome do personagem Star Wars no meio de toda essa informação:
1- Se olharmos bem, um json é constituído de "chave":"valor"
ou no inglês "key":"value"
:
2- E a key name
está dentro de um array
(matriz) chamado results
:
3- Então para filtrarmos, poderíamos começar com:
curl https://swapi.dev/api/people | jq '.results'
Vamos entender o que aconteceu aqui:
Adicionamos ao final do nosso comando
| jq '.results'
Esse
'.results'
é um filtro que estamos dizendo ao jq"hey, pegue todos os dados do array (matriz) chamado results e imprima o json desses itens".
Com isso as primeiras linhas que não fazem parte de
results
foram digamos assim "ignoradas".
Avançando ainda mais...
4- Se continuarmos olhando com atenção, poderemos ver que esse array
(matriz) results
possui uma lista de itens, onde:
a primeira posição do
array
(matriz) é oindex
(índice)0
e o nome éLuke Skywalker
a segunda posição do
array
(matriz) é oindex
(índice)1
e o nome é oC-3PO
Então podemos limitar nosso filtro passando como index (índice) 0
e isso nos retornará o nome Luke Skywalker
como previsto:
curl https://swapi.dev/api/people | jq '.results[0]'
Vamos entender o que aconteceu aqui:
Adicionamos ao final do nosso comando
| jq '.results[0]'
Esse
'.results[0]'
é um filtro que estamos dizendo ao jq"hey, pegue todos os dados do array (matriz) chamada results e imprima o index (índice) 0 (primeira posição da matriz) em um json".
Com isso o segundo item dessa matriz, no caso o
C-3PO
é digamos assim "ignorado", pois limitamos para o index (índice)0
em nosso filtro.
Avançando mais e mais...
5- Até agora já descobrimos como chegar nesse valor, mas lembra que queríamos apenas o nome?
Bom, então só precisamos informar essa propriedade para o jq
:
curl https://swapi.dev/api/people | jq '.results[0] | .name'
Mas aqui vale mais um pouco da sua atenção, vamos dividir nosso comando para entendermos melhor:
curl https://swapi.dev/api/people
→ faz umrequest
para a API do filme Star Wars| jq '.results[0]
→ filtra os dados do index0
no arrayresults
| .name'
→ imprime na saída a propriedadename
do index0
noarray results
Observe que depois do filtro, adicionamos novamente um "pipe
" |
, esse último bloco é responsável por "imprimir" as informações para nós como definirmos, isso é a mesma coisa que stdout
. Grave essa informação, pois ela será útil em todos os próximos comandos, onde vamos mudar e manipular a forma que esses dados serão apresentados para nós.
Agora ao invés de listar apenas o nome do index (índice) 0 do array (primeira posição da matriz), vamos listar todos os nomes dessa matriz, para isso é só removermos o 0 de .results[0], ficando assim:
curl https://swapi.dev/api/people | jq '.results[] | .name'
Vamos entender o que aconteceu aqui:
Adicionamos ao final do nosso comando
| jq '.results[] | .name'
Esse
'.results[] | .name'
é um filtro que estamos dizendo ao jq"hey, pegue todos os dados do array (matriz) chamada results (ele inteiro sem qualquer índice) e imprima a propriedade name".
Avançando mais, mais e mais...
6- Legal, já conseguimos listar o nome de todos, mas eles ainda estão digamos assim "jogados", "soltos", vamos consertar isso:
curl https://swapi.dev/api/people | jq '.results[] | {name: .name}'
Vamos entender o que aconteceu aqui:
Adicionamos ao final do nosso comando
| jq '.results[] | {name: .name}'
Esse
'.results[] | {name: .name}'
é um filtro que estamos dizendo ao jq"hey, pegue todos os dados do array (matriz) chamada results (ele inteiro sem qualquer índice) e imprima a key (chave) name com o value (valor) da propriedade name entre {}".
Avançando mais, mais, mais e ainda mais...
7- Estamos melhorando, mas ainda podemos ver que essas informações estão "jogadas", não há formatação json
e nem vírgulas no final de cada {}
, vamos consertar isso:
curl https://swapi.dev/api/people | jq '[.results[] | {name: .name}]'
Vamos entender o que aconteceu aqui:
A única diferença é que adicionamos colchetes
[]
no início e final do nosso filtro'[.results[] | {name: .name}]'
Então estamos dizendo ao jq aqui
"hey coloque o resultado desse filtro dentro de um array (matriz)".
Avançando e avançando...
8- Até agora vimos exemplos somente com uma propriedade name
, mas e se quisermos usar várias propriedades juntas? A resposta é simples, separe por vírgulas, por exemplo:
curl https://swapi.dev/api/people | jq '[.results[] | {name: .name, eye_color: .eye_color}]'
Vamos entender o que aconteceu aqui:
A única diferença é que separamos as propriedades
name
eeye_color
por vírgulas → ou seja →'[.results[] | {name: .name, eyecolor: .eye_color}]'
Então estamos dizendo ao jq aqui
"hey coloque o resultado desse filtro dentro de um array (matriz) com as keys (chaves) name e eye_color com os values (valores) das respectivas propriedades".
Último avanço...
9- Mas e se já tivermos um valor e quisermos fazer uma pesquisa? Por exemplo queremos montar um novo array (matriz) com os nomes dos personagens que possuem olhos azuis, faremos um select
:
curl https://swapi.dev/api/people | jq '[.results[] | select(.eye_color=="blue") | {name: .name}]'
Vamos entender o que aconteceu aqui:
A única diferença é que adicionamos
select(.eye_color=="blue")
.Então estamos dizendo ao jq aqui
"hey vá para a array (matriz) results, ache o value (valor) blue (azul) na propriedade eye_color de cada item e coloque o resultado desse filtro dentro de um array (matriz) com a keys (chave) name com o seu respectivo value (valor).
jq
funciona e como você pode manipular a saída json
para suas preferências ou caso de uso.Use JQ para Scripts
No seu dia a dia você vai se deparar várias vezes com a necessidade de obter dados de uma saída json
, mas isso não se aplica somente a sistemas web, você também vai notar que precisará disso principalmente para seus scripts funcionarem corretamente, por exemplo pode ser comum você precisar obter o ID de uma instância na AWS, então para isso você faria:
aws ec2 describe-instances
Esse comando do AWS CLI faz uma chamada na API da AWS e te retornaria uma saída json
com muitas informações, por exemplo:
Mas nós só queremos o ID dessa instância, é aqui que entra o jq
e tudo que vimos nesse artigo, então bastaria nós retornarmos o valor da key InstanceID
:
aws ec2 describe-instances | jq '.Reservations[] | .Instances[] | {Id: .InstanceId}'
Vamos entender o que aconteceu aqui:
Adicionamos ao final do nosso comando AWS CLI
| jq '.Reservations[] | .Instances[] | {Id: .InstanceId}'
| jq '.Reservations[]
→ jq está indo no arrayReservations
| .Instances[]
→ jq está indo no arrayInstances
| {Id: .InstanceId}'
→ jq está "imprimindo" a keyId
com o valueInstanceId
E essa informação poderia ser muito útil para um script que agenda o ligar/desligar dessa instância por exemplo.
Outro exemplo poderia ser se você estiver usando o AWS ECS Fargate para orquestrar seus contêineres e como parte de um Pipeline automático, você gostaria de fazer o Deploy da sua nova imagem em uma nova Task, para isso seria importante você descobrir o ID dessa Task, então você faria:
aws ecs list-tasks --cluster <clusterName>
Observe que é retornado um ARN que é o nome completo de um recurso da AWS, mas nós só precisamos do ID que está localizado depois do último /
, então usaríamos o jq aqui para dividir esses caracteres assim:
aws ecs list-tasks --cluster <clusterName> | jq -Mr '.taskArns[] | split("/")[-1]'
Vamos entender o que aconteceu aqui:
Adicionamos no final do nosso comando AWS CLI
| jq -Mr '.taskArns[] | split("/")[-1]'
| jq -Mr '.taskArns[]
→ jq está indo para o arraytaskArns
| split("/")[-1]'
→ jq está "imprimindo" o último bloco depois da/
que é o ID
Conclusão
Esses foram alguns exemplos reais e práticos de como usar o jq
e de como ele pode ser útil no seu dia a dia, obviamente você poderia fazer várias combinações e filtros diferentes e para diferentes ferramentas como inspecionar containers do docker, kubernetes e muitas outras coisas.