JSON em shell script

json-shell_abertura

Não é novidade que diversos programas e serviços* retornam arquivos no formato JSON e que estes podem ser processadas de modo (quase) transparente por diversas linguagens de programação. Mas há alguma maneira de trabalhar com estes arquivos diretamente em shell script? Ou seja, pegar a saída “cuspida”em JSON de alguma ferramenta e interpretá-lo de forma “natural” sem recorrer a sequências de awk, grep, sed etc?

Pesquisando eu descobri que sim. Com a ajuda do jq programa que, conforme descrito na página do projeto, é uma espécie de sed para arquivos JSON. 🙂

(*) Só lembrando que o AWS CLI pode ser configurado para exibir suas saídas em JSON.

Instalando o ‘jq’

A instalação é simples, ele está facilmente disponível para Linux (nas distribuições Arch Linux, Debian/Ubuntu, Fedora e openSUSE), FreeBSD, (Mac)OS X, Solaris e Windows — mas pode ser compilado para qualquer sistema operacional POSIX.

JSON de exemplo

Para os exemplos resolvi pegar um dos arquivos JSON usados no cluster do Consul:

Motivo? Ele é pequeno, simples e tem (quase) tudo que é necessário para os exemplos a seguir.

Usando o ‘jq’

O jq funciona a partir de filtros, ou seja, você envia um arquivo JSON e ele extrai/processa aquilo de acordo com o(s) filtro(s) indicado(s) e exibindo o resultado em STDOUT. O filtro mais simples é o “.”:

$ echo $( cat mongodb.json | tr "[:space:]*" "\000" ) | jq '.'
{
  "service": {
    "name": "mongodb",
    "tags": [
      "database",
      "db",
      "nosql"
    ],
    "port": 28017,
    "check": {
      "tcp": "localhost:28017",
      "interval": "20s"
    }
  }
}

Ele significa “todo o JSON” e o que este filtro faz é retornar o próprio arquivo JSON formatado e até colorido se o terminal suportar cores. A inserção do comando tr no meio do comando foi para propositalmente enfeiar o arquivo, fazendo-o ficar assim:

$ echo $( cat mongodb.json | tr "[:space:]*" "\000" )
{"service":{"name":"mongodb","tags":["database","db","nosql"],"port":28
017,"check":{"tcp":"localhost:28017","interval":"20s"}}}

Isto aqui foi só para demonstrar que o jq interpretou o arquivo e não simplesmente o jogou na tela. 🙂

Operações básicas

Para recuperar o valor da chave “name” (lembrando que ela está dentro de “service”) faço:

$ cat mongodb.json | jq '.service.name'
"mongodb"

Para listar todos os elementos dentro da chave “tags”, que é um array, uso:

$ cat mongodb.json | jq --compact-output '.service.tags'
["database","db","nosql"]

O parâmetro “–compact-output” ou apenas “-c” serve para retornar uma versão compactada do arquivo JSON sem tantas quebras de linha e tabulações.

Desejando apenas saber quantos elementos o array possui:

$ cat mongodb.json | jq '.service.tags | length'
3

A função do operador pipe (“|”) é a de concatenar os filtros fazendo com que a saída dele sirva de entrada para o próximo (sim, igualzinho no shell, portanto preste atenção nas aspas).

E para recuperar elementos específicos, no caso o primeiro e o terceiro, dentro do array:

$ cat mongodb.json | jq '.service.tags[0,2]'
"database"
"nosql"

Se você não indicar os elementos, deixando apenas os colchetes (“[ ]”), todo o array será recuperado.

Operações mais “complexas”

Que tal somar 10 ao valor 28017 da chave “port”? Isto pode ser feito assim:

$ cat mongodb.json | jq '.service.port + 10'
28027

Quando utilizado com strings o operador “+” irá concatená-las e com arrays irá mesclar seus elementos.

Ainda estão disponíveis subtração, multiplicação, divisão, módulo etc. Mas aí precisarei trocar de JSON, no “Um outro exemplo de AngulaJS” há um arquivo JSON que contém notas para o cálculo da média.

$ cat exemplo-abj-2.json | jq '.[].notas | add / 4'  
8.2575
7.5525
6.4125
8.5105

Aqui o filtro “add” está sendo usado para somar todos os itens do array.

Para listar as chaves presentes dentro do arquivo JSON, faça:

$ cat mongodb.json | jq -c '.service | keys'
["check","name","port","tags"]

E para fazer a remoção de uma chave:

$ cat mongodb.json | jq -c 'del(.service.check)'
{"service":{"name":"mongodb","tags":["database","db","nosql"],"port":28
017}}

Repare que neste caso é importante recuperar o conteúdo da saída pois o arquivo original não será alterado.

Fechando…

Na documentação do jq é possível conhecer os outros (vários) filtros disponíveis para a manipulação de arquivos JSON. Os filtros listados acima são uma pequena amostra dos recursos disponíveis. Há o suficiente deles para a execução de diversas tarefas, até mesmo com a possibilidade de se incluir condições com operadores lógicos, laços, expressões regulares etc.

E ainda é possível juntar tudo isto para criar funções e assim produzir seus próprios filtros!

Anúncios

Um comentário sobre “JSON em shell script

  1. Pingback: JSON em shell script - Linux em Ação XYZ

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s