Introdução
Programas tradicionais como sed, grep ou awk, utilizados para automatização de tarefas em ambientes unix e para processamento de textos, são flexíveis o suficiente para atender às exigências de tratamento de dados em formatos modernos, tal qual json.
No entanto, recomenda-se o uso de jq - ferramenta de linha de comando que facilita o processamento de dados estruturados no formato baseado na sintaxe JavaScript, que é o padrão utilizado para a comunicação de APIs e serviços web, considerando que as funções nativas dispensam o esforço extra de codificação exigido pelo uso de ferramentas clássicas, embora em algumas situações não rejeitem o auxílio de utilitários consagrados e de outras ferramentas de visualização, como csvlook e youplot.
JSON é um acrônimo para JavaScript objetc notation. Sua principal característica é o uso de arrays, estrutura especial de dados capaz de armazenar elementos de diversos tipos, como uma lista de objetos delimitada por colchetes [{}].
Objetivo
Explorar algumas funcionalidades da ferramenta jq, úteis para a manipulação de dados no formato json.
Coleta de dados
Utilizamos os dados abertos da Prefeitura Municipal de Três Corações/MG, relativos às despesas de pessoal, disponíveis no Portal de Transparência do município, que são disponibilizados via API, através do link trescoracoes-mg.portaltp.com.br/api/transparencia.asmx/json_servidores?ano=2017&mes=1.
Cole-o na barra de endereços do navegador ou digite na linha de
comando do terminal:
curl -s -k
trescoracoes-mg.portaltp.com.br/api/transparencia.asmx/json_servidores?ano=2017&mes=1..
Altere os parâmetros “ano” e “mês”, para obter os dados desejados, e salve o arquivo no diretório de trabalho.
Utilizado no presente artigo, o arquivo json_servidores.xml do mês
11/2022 pode ser baixado em:
https://drive.google.com/file/d/11tC1DnsD0hK3dvosAGVyRdPMI-IOvRJN/view?usp=sharing.
Tarefa de pré-processamento
Embora a estrutura de dados esteja no formato JSON, o arquivo contém a extensão XML.
XML, acrônimo para extensible markup language, pode ser utilizado para criar dados estruturados, com a utilização de tags de abertura (< _ >) e fechamento(</ _ >).
Carregamos o arquivo para visualizar o cabeçalho:
cat json_servidores.xml | lessNo cabeçalho do arquivo constam duas declaçaões, delimitadas pelas tags (< >):
Na primeira, estão descritas a versão do protocolo XML (1.0) e o
padrão de codificação (Unicode utf-8).
Na segunda, consta
um espaço reservado para serviços web em XML, que estejam em
desenvolvimento, cujo domínio (URI) pertence à Microsoft.
A seguir, o sinal gráfico para colchete de abertura “[” indica o início de um array, que contém objetos delimitados por chaves “{}”, separados por vírgula. Cada objeto contém o par “key:value”, que é a forma padrão de representação de dados json.
Excluímos o cabeçalho xml e atribuímos ao arquivo a extensão json:
sed -e 's/<[^>]*>//g' json_servidores.xml > servidores.jsonVerificamos quais chaves compõem o array:
jq -c '.[0] | keys_unsorted' servidores.json## ["ano","mes","unidade_gestora","documento","nome","data_admissao","data_demissao","situacao","matricula","profissao","cargo","regime","centro_custo","horas_semanais","horas_mensais","jornada","local","secretaria","divisao","secao","ato_nomeacao","data_nomecao","numero_concurso","nome_concurso","data_concurso","data_homologacao","numero_lei","nome_padrao","valor_padrao","nome_rem01","valor_rem01","nome_rem02","valor_rem02","nome_rem03","valor_rem03","nome_rem04","valor_rem04","nome_rem05","valor_rem05","nome_rem06","valor_rem06","nome_rem07","valor_rem07","nome_rem08","valor_rem08","nome_rem09","valor_rem09","nome_rem10","valor_rem10","nome_rem11","valor_rem11","nome_rem12","valor_rem12","nome_rem13","valor_rem13","nome_rem14","valor_rem14","nome_rem15","valor_rem15","nome_rem16","valor_rem16","nome_rem17","valor_rem17","nome_rem18","valor_rem18","nome_rem19","valor_rem19","nome_rem20","valor_rem20","nome_rem21","valor_rem21","nome_rem22","valor_rem22","nome_rem23","valor_rem23","nome_rem24","valor_rem24","nome_rem25","valor_rem25","nome_rem26","valor_rem26","nome_rem27","valor_rem27","nome_rem28","valor_rem28","nome_rem29","valor_rem29","nome_rem30","valor_rem30","nome_rem31","valor_rem31","nome_rem32","valor_rem32","nome_rem33","valor_rem33","nome_rem34","valor_rem34","nome_rem35","valor_rem35","nome_rem36","valor_rem36","nome_rem37","valor_rem37","nome_rem38","valor_rem38","nome_rem39","valor_rem39","nome_rem40","valor_rem40"]
Extraímos o par “key:value” do primeiro elemento da lista, para facilitar a seleção das chaves com base nos valores atribuídos. Excluímos o objeto “nome”, para evitar a exposição do servidor, bem como os demais objetos com valores nulos (null), zerados (0) ou vazios(““).
jq '.[0] | del(.nome)' servidores.json |
jq 'del(.[] | select(. == 0 or . == null or . == ""))'## {
## "ano": "2022",
## "mes": "11",
## "unidade_gestora": "Prefeitura Municipal de Tres Coracoes",
## "documento": "***.608.176-**",
## "data_admissao": "09/03/2021 00:00:00",
## "data_demissao": "25/10/2022 00:00:00",
## "situacao": "Demitido",
## "matricula": "025910",
## "profissao": "ENFERMEIRO",
## "cargo": "ENFERMEIRO",
## "regime": "Serv.Publ.Nao Efetiv",
## "centro_custo": "BANCO PSF",
## "horas_semanais": "200:00",
## "horas_mensais": "200:00",
## "jornada": "30/12",
## "local": "Secretaria Municipal de Saude",
## "secretaria": "Saude da Familia - PSF - CTD. F. 38099",
## "divisao": "Saude da Familia - PSF - CTD. F. 38099",
## "secao": "Saude da Familia - PSF - CTD. F. 38099",
## "nome_padrao": "00-19-09",
## "valor_padrao": 3152.17,
## "nome_rem01": "Salario Base",
## "nome_rem02": "13º Salario",
## "nome_rem03": "Ferias",
## "nome_rem04": "Outras Remuneracoes",
## "valor_rem04": 369.8,
## "nome_rem05": "Salario Bruto",
## "valor_rem05": 369.8,
## "nome_rem06": "Descontos Previdencia",
## "nome_rem07": "Desconto IRRF",
## "nome_rem08": "Outros Descontos",
## "valor_rem10": 369.8
## }
Extração de dados com jq
O utilitário jq possui funções nativas que ajudam na extração de dados:
Há quantos elementos na lista?
jq length servidores.json## 2733
A estrutura organizacional da prefeitura é composta por quantos cargos distintos?
jq -r 'group_by(.cargo) |
[.[] | {cargo: .[0].cargo, count: . | length}] |
length' servidores.json## 319
Podemos calcular a quantidade de cargos por local.
Por exemplo: a Secretaria de Educação possui quantos
cargos?
< servidores.json jq -r '[.[] |
select(.local | contains("Educacao"))] |
[ group_by(.cargo)[] |
{cargo: .[0].cargo, count: length}] |
length'## 61
Quantas pessoas ocupam cargos na cadeia de comando e assessoramento, abaixo do Executivo?
A princípio, utilizamos somente código jq:
ccomis='[
"SECRETARIO MUNICIPAL", "SECRETARIO ADJUNTO", "DIRETOR", "CHEFE", "ASSESSOR SETORIAL"
]'
jq --argjson ccomis "$ccomis" '[.[] |
select( .cargo | contains($ccomis[])) |
select( .situacao == "Ativo")] |
[.[]| .cargo | split(" ")[0:2] | join(" ")] |
[reduce .[] as $item ({}; .[$item] += 1) |
to_entries[]] | from_entries' servidores.json## {
## "CHEFE DA": 72,
## "SECRETARIO ADJUNTO": 11,
## "DIRETOR DO": 57,
## "DIRETOR (A)": 17,
## "ASSESSOR SETORIAL": 36,
## "SECRETARIO MUNICIPAL": 14,
## "DIRETOR DE": 1
## }
Em seguida, reformulamos a resposta com loop for no bash:
#!/bin/bash -
# Utilizamos shell script para iterar o array de critérios de busca
# Depois de salvo, tornamos o arquivo executável, com o comando:
# sudo chmod +x cargos.sh
# Em seguida, executamos o shell script na linha de comando
cargos=("SECRETARIO MUNICIPAL" "SECRETARIO ADJUNTO"
"DIRETOR" "CHEFE" "ASSESSOR SETORIAL")
for i in "${!cargos[@]}"; do
cargo=${cargos[i]}
qte=$(jq --arg cargo "$cargo" '[.[] |
select(.cargo | contains($cargo)) |
select( .situacao == "Ativo").cargo] |
length' servidores.json)
echo "${cargos[i]}": $qte
done./cargos.sh## SECRETARIO MUNICIPAL: 14
## SECRETARIO ADJUNTO: 11
## DIRETOR: 75
## CHEFE: 72
## ASSESSOR SETORIAL: 36
Quantas pessoas exercem o cargo de “Diretor de Departamento”, posto que no levantamento anterior também estão incluídos os “Diretores de Escola”?
< servidores.json jq -r '[ .[] |
select( .situacao == "Ativo") |
select( .cargo |
contains("DIRETOR D")).cargo ] |
length '## 58
Sabendo que a acumulação de cargos públicos, seguindo algumas regras, é permitida para professores e profissionais de saúde, calculamos quantos servidores se enquadram nessa situação:
< servidores.json jq '[.[].nome] |
[reduce .[] as $item ({}; .[$item] += 1) |
to_entries[] |
select(.value > 1)] |
from_entries | length'## 164
Diante disso, podemos determinar com precisão quantas pessoas únicas participam da folha de pagamento do mês 11/2022:
< servidores.json jq '[.[].nome] |
reduce .[] as $item ({}; .[$item] += 1) |
length'## 2569
Qual a situação funcional dos servidores?
jq -r 'group_by(.situacao) | [.[] | {situacao: .[0].situacao, count: . | length}] |
sort_by(.count) | reverse | .[]| [.situacao, .count] | @csv' servidores.json |
uplot bar -d, -t "Situação funcional"## Situação funcional
## ┌ ┐
## Ativo ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 2514.0
## Funcionario de Ferias ┤■ 73.0
## Licenca Para Tratamento de Saude ┤■ 50.0
## Demitido ┤ 34.0
## Licenca sem Remuneracao ┤ 27.0
## Licenca Premio ┤ 11.0
## Licenca Maternidade ┤ 9.0
## Pagamento realizado por outro Orgao ┤ 8.0
## Suspensao de Pagamento ┤ 2.0
## Afastamento Por Acidente de Trabalho ┤ 2.0
## Licenca por Motivo de Doenca em Pessoa da Familia ┤ 1.0
## Licenca com Remuneracao ┤ 1.0
## Aposentado ┤ 1.0
## └ ┘
Qual a natureza do vínculo empregatício?
jq -r 'group_by(.regime) | [.[] | {regime: .[0].regime, count: . | length}] |
sort_by(.count) | reverse | .[]| [.regime, .count] | @csv' servidores.json |
uplot bar -d, -t "Natureza do vínculo"## Natureza do vínculo
## ┌ ┐
## Serv.Publ.Nao Efetiv ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 1358.0
## Serv.Efetivo ┤■■■■■■■■■■■■■■■■■ 712.0
## Serv Efet Prev Cap ┤■■■■■■■■■■ 430.0
## Serv.Contr.Comiss. ┤■■ 91.0
## Serv.Efetiv.Comiss. ┤■ 55.0
## Efet Comiss Prev Cap ┤■ 32.0
## Ag.Politico Contrat. ┤ 20.0
## Diretores Efetivos ┤ 15.0
## Ag.Politico Efetivo ┤ 7.0
## Pro-Labore ┤ 6.0
## Ag Pol Efet Prev Cap ┤ 4.0
## Diret Efet Prev Cap ┤ 1.0
## Diret Contratados ┤ 1.0
## Ag Politico Efetivo RGPS ┤ 1.0
## └ ┘
Qual a lotação dos servidores por secretaria?
jq -r 'group_by(.local) | [.[] | {local: .[0].local, count: . | length}] |
sort_by(.count) | reverse | .[]| [.local, .count] | @csv' servidores.json |
uplot bar -d, -t "Lotação dos servidores"## Lotação dos servidores
## ┌ ┐
## Secretaria de Educacao ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 1172.0
## Secretaria Municipal de Saude ┤■■■■■■■■■■■■■■■■■■■■ 731.0
## Secretaria Municipal de Obras e Servicos Publicos ┤■■■■■■■ 240.0
## Secretaria de Desenvolvimento Social ┤■■■■ 151.0
## Secretaria de Administracao e Recursos Humanos ┤■■ 82.0
## Secretaria de Financas ┤■ 51.0
## Secretaria do Esporte ┤■ 49.0
## Secretaria de Governo ┤■ 46.0
## Secretaria M de Planejamento e Desenv Urbano ┤■ 41.0
## Secretaria Municipal do Meio Ambiente e Defesa Ani ┤■ 35.0
## Secretaria Municipal de Seguranca Publica e Mob Ur ┤■ 30.0
## Secretaria de Lazer, Turismo e Cultura ┤■ 29.0
## Secretaria Municipal de Desenvolvimento Economico ┤■ 25.0
## Secretaria Municipal de Agricultura e Pecuaria ┤■ 23.0
## Procuradoria ┤ 12.0
## Secretaria Municipal de Controle Interno ┤ 10.0
## Secretaria de Comunicacao e Relacoes institucionai ┤ 6.0
## └ ┘
Qual a alocação de recursos humanos por centro de custo?
jq -r 'group_by(.centro_custo) | [.[] | {centro_custo: .[0].centro_custo, count: . |
length}] | sort_by(.count) | reverse | .[]| [.centro_custo, .count] |
@csv' servidores.json |
uplot bar -d, -t "Alocação de recursos humanos por centro de custo"## Alocação de recursos humanos por centro de custo
## ┌ ┐
## Fundeb ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 889.0
## Geral ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 794.0
## SAUDE 15 ┤■■■■■■■■■■■■■■■■■ 449.0
## 25 Educacao ┤■■■■■■■■■■ 272.0
## BANCO PSF ┤■■■■■■■■■■ 269.0
## Tesouraria ┤■■ 58.0
## Secretaria de Educacao ┤ 1.0
## Secretaria Municipal de Controle Interno ┤ 1.0
## └ ┘
Qual o gasto com o funcionalismo em 11/2022?
jq 'map(.valor_rem05) | add | floor' servidores.json## 9523405
Formatamos a saída para a moeda corrente (com uma nova sintaxe para acesso ao objeto submetido à operação aritmética da adição):
jq '[.. | objects | .valor_rem05] | add' servidores.json |
awk '{printf "R$ %'\''.2f\n", $0}'## R$ 9.523.405,09
Qual a despesa de pessoal por centro de custo?
jq -r 'group_by(.centro_custo) |
map({centro_custo: .[0].centro_custo, total: map(.valor_rem05) | add}) |
sort_by(.total) | reverse | [.[] | select(.total > 0)] | (first |
keys_unsorted) as $keys | map([to_entries[] | .value]) as $rows |
$keys,$rows[] | join(":")' servidores.json |
awk 'BEGIN{ FS=OFS=":" } NR>1 { $2=sprintf ("R$ %'\''.2f", $2) }1' |
csvlook -d":" ## | centro_custo | total |
## | ------------ | --------------- |
## | Geral | R$ 2.897.591,48 |
## | Fundeb | R$ 2.727.913,06 |
## | SAUDE 15 | R$ 1.682.549,77 |
## | BANCO PSF | R$ 1.317.121,78 |
## | 25 Educacao | R$ 610.983,23 |
## | Tesouraria | R$ 287.245,77 |
Qual a média salarial por centro de custo, sabendo que a mediana é a medida de tendência central mais adequada para distribuições assimétricas?
jq -r 'group_by(.centro_custo) |
map({centro_custo: .[0].centro_custo, media_salarial: map(.valor_rem05) |
(sort|if length%2==1 then.[length/2|floor]else[.[length/2-1,length/2]]|
add/2 end)})|sort_by(.media_salarial)|reverse|[.[]|select(.media_salarial>0)]|
(first | keys_unsorted) as $keys | map([to_entries[] | .value]) as $rows |
$keys,$rows[] | join(":")' servidores.json |
awk 'BEGIN{ FS=OFS=":" } NR>1 { $2=sprintf ("R$ %'\''.2f", $2) }1' |
csvlook -d":"## | centro_custo | media_salarial |
## | ------------ | -------------- |
## | Tesouraria | R$ 3.869,26 |
## | SAUDE 15 | R$ 3.162,43 |
## | Geral | R$ 3.017,19 |
## | BANCO PSF | R$ 2.908,80 |
## | Fundeb | R$ 2.596,43 |
## | 25 Educacao | R$ 1.838,48 |
Podemos também determinar a despesa salarial para uma profissão
ou cargo específico.
Nesse caso, utilizamos a string “PROF”
como critério de busca, para localizar toda ocorrência que contenha, em
qualquer parte, o padrão definido para identificar o cargo de
professor:
< servidores.json jq -r '[.[] |
select(.cargo | contains("PROF"))] |
map({"key": .cargo, "value": .valor_rem05}) |
sort_by(.value) | reverse | [.[]| select(.value > 0)] |
map(.value) | add' |
awk '{printf "R$ %'\''.2f\n", $0}'## R$ 2.318.158,16
jq possui funções nativas para calcular valores mínimo e máximo:
jq '[.[].valor_rem05] | {"Mínimo":min, "Máximo":max}' servidores.json## {
## "Mínimo": 0,
## "Máximo": 41784.33
## }
O teto remuneratório do funcionalismo público municipal é limitado pelo subsídio do prefeito:
jq '.[] | select(.cargo == "PREFEITO MUNICIPAL").valor_padrao' servidores.json |
awk '{printf "R$ %'\''.2f\n", $0}'## R$ 20.801,85
O valor extremo superior representa um supersalário?
jq -r '.[] | select(.valor_rem05 == 41784.33) |
{"salário base": .valor_padrao}' servidores.json## {
## "salário base": 12374.38
## }
Quais verbas salariais contribuiram para gerar esse valor atípico?
< servidores.json jq -r '.[] | select(.valor_rem05 == 41784.33) |
{"data admissao": .data_admissao, "data demissao": .data_demissao,
"situacao funcional": .situacao, "cargo": .cargo, "salario base": .valor_padrao,
"13 salario": .valor_rem02, "Ferias": .valor_rem03, "Outras remuneracoes": .valor_rem04}' ## {
## "data admissao": "12/05/2022 00:00:00",
## "data demissao": "16/11/2022 00:00:00",
## "situacao funcional": "Demitido",
## "cargo": "MEDICO - PSF",
## "salario base": 12374.38,
## "13 salario": 10214.46,
## "Ferias": 11286.06,
## "Outras remuneracoes": 7909.43
## }
No extremo oposto, quantos servidores tiveram a remuneração zerada em 11/2022:
jq '[.[] | select(.valor_rem05 == 0).valor_rem05] | length' servidores.json## 53
Por quais motivos os salários foram zerados?
< servidores.json jq -r '[.[] | select(.valor_rem05 == 0)] |
[ group_by(.situacao)[] | {situacao: .[0].situacao, count: length }] |
sort_by(.count) | reverse | .[] | [.situacao, .count] | @tsv'## Licenca sem Remuneracao 27
## Licenca Para Tratamento de Saude 15
## Pagamento realizado por outro Orgao 8
## Afastamento Por Acidente de Trabalho 2
## Suspensao de Pagamento 1
Podemos utilizar código nativo em jq para calcular estatísticas básicas:
< servidores.json jq -r '[.[] | select(.valor_rem05>0).valor_rem05] |
sort| {mean:(add/length), median:(sort|if length%2==1 then.[length/2
|floor]else[.[length/2-1,length/2]]|add/2 end),stdev:((add / length) as $mean |
(map(. - $mean | . * .) | add) / (length - 1) | sqrt)} |
.skewness = 3 * (.mean - .median) / .stdev'## {
## "mean": 3553.5093619402965,
## "median": 2908.8,
## "stdev": 2467.6956446432387,
## "skewness": 0.783779024783468
## }
Fazemos reuso do código para calcular as estatísticas básicas relativas ao subconjunto do cargo de professor:
< servidores.json jq -r '[.[] |
select(.cargo | contains("PROF"))] |
map({"Salario": .valor_rem05}) | [.[]| select(.Salario > 0)] |
map(.Salario) | sort |
{min:min, max:max, mean:(add/length), median:(sort|if length%2==1 then.[length/2
|floor]else[.[length/2-1,length/2]]|add/2 end),stdev:((add / length) as $mean |
(map(. - $mean | . * .) | add) / (length - 1) | sqrt)} |
.skewness = 3 * (.mean - .median) / .stdev'## {
## "min": 412.05,
## "max": 13904.35,
## "mean": 3325.9084074605394,
## "median": 2910.84,
## "stdev": 1337.1492610146738,
## "skewness": 0.931238761958941
## }
Podemos recorrer ao auxílio de csvstat para simplificar a tarefa:
jq '.[] | select(.valor_rem05>0).valor_rem05' servidores.json | csvstat -H ## /usr/local/lib/python3.10/dist-packages/agate/table/from_csv.py:70: RuntimeWarning: Error sniffing CSV dialect: Could not determine delimiter
## 1. "a"
##
## Type of data: Number
## Contains null values: False
## Unique values: 1411
## Smallest value: 133,73
## Largest value: 41.784,33
## Sum: 9.523.405,09
## Mean: 3.553,509
## Median: 2.908,8
## StDev: 2.467,696
## Most common values: 2.369,49 (200x)
## 1.437,29 (120x)
## 2.908,8 (95x)
## 2.578,99 (53x)
## 2.269,49 (53x)
##
## Row count: 2680
Ou executar um script R na linha de comando:
jq '.[] | select(.valor_rem05>0).valor_rem05' servidores.json |
R -q -e "x <- read.csv('stdin', header = F); summary(x); sd(x[ ,1])" ## > x <- read.csv('stdin', header = F); summary(x); sd(x[ ,1])
## V1
## Min. : 133.7
## 1st Qu.: 2170.5
## Median : 2908.8
## Mean : 3553.5
## 3rd Qu.: 4086.6
## Max. :41784.3
## [1] 2467.696
## >
## >
A inspeção visual dos dados pode ser feita com o histograma de frequência:
jq '.[] | select(.valor_rem05>0).valor_rem05' servidores.json |
sort -gr | uplot hist --nbins 20 ## ┌ ┐
## [ 0.0, 2000.0) ┤▇▇▇▇▇▇▇▇▇▇▇ 477
## [ 2000.0, 4000.0) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1518
## [ 4000.0, 6000.0) ┤▇▇▇▇▇▇▇▇▇ 420
## [ 6000.0, 8000.0) ┤▇▇▇ 153
## [ 8000.0, 10000.0) ┤▇ 61
## [10000.0, 12000.0) ┤ 14
## [12000.0, 14000.0) ┤ 13
## [14000.0, 16000.0) ┤ 4
## [16000.0, 18000.0) ┤ 3
## [18000.0, 20000.0) ┤ 10
## [20000.0, 22000.0) ┤ 4
## [22000.0, 24000.0) ┤ 0
## [24000.0, 26000.0) ┤ 2
## [26000.0, 28000.0) ┤ 0
## [28000.0, 30000.0) ┤ 0
## [30000.0, 32000.0) ┤ 0
## [32000.0, 34000.0) ┤ 0
## [34000.0, 36000.0) ┤ 0
## [36000.0, 38000.0) ┤ 0
## [38000.0, 40000.0) ┤ 0
## [40000.0, 42000.0) ┤ 1
## └ ┘
## Frequency
Ou com o diagrama de caixa e bigode (boxplot):
jq '.[] | select(.valor_rem05>0).valor_rem05' servidores.json |
sort -gr | uplot boxplot -t Variabilidade## Variabilidade
## ┌ ┐
## ╷┬┐ ╷
## 1 ├│├─────────────────────────────┤
## ╵┴┘ ╵
## └ ┘
## 0 25000 50000
Conversão para o formato csv:
Por fim, filtramos os campos desejados para geração do arquivo csv, que permite a análise refinada dos dados com ferramentas mais robustas.
jq -r 'map({matricula, situacao, data_admissao,
data_demissao, profissao, cargo, regime, local, centro_custo, valor_rem05}) |
(first | keys_unsorted) as $keys |
map([to_entries[] |
.value]) as $rows |
$keys,$rows[] | join(";")' servidores.json |
head## matricula;situacao;data_admissao;data_demissao;profissao;cargo;regime;local;centro_custo;valor_rem05
## 025910;Demitido;09/03/2021 00:00:00;25/10/2022 00:00:00;ENFERMEIRO;ENFERMEIRO;Serv.Publ.Nao Efetiv;Secretaria Municipal de Saude;BANCO PSF;369.8
## 000003;Ativo;01/12/1986 00:00:00;;AGENTE DE SERVICOS PUBLICOS;AGENTE DE SERVICOS PUBLICOS;Serv.Efetivo;Secretaria Municipal de Obras e Servicos Publicos;Geral;4484.84
## 000008;Ativo;20/03/1984 00:00:00;;AGENTE DE SERVICOS PUBLICOS;AGENTE DE SERVICOS PUBLICOS;Serv.Efetivo;Secretaria do Esporte;Geral;4879.73
## 000015;Ativo;24/01/1984 00:00:00;;ENGENHEIRO MECANICO;ENGENHEIRO MECANICO;Serv.Efetivo;Secretaria Municipal de Desenvolvimento Economico;Geral;12452.5
## 000016;Ativo;24/04/1990 00:00:00;;AGENTE DE SERVICOS PUBLICOS;AGENTE DE SERVICOS PUBLICOS;Serv.Efetivo;Secretaria Municipal de Obras e Servicos Publicos;Geral;5757.3
## 000017;Ativo;01/03/1986 00:00:00;;AGENTE DE GESTAO ADMINISTRATIVA;AGENTE DE GESTAO ADMINISTRATIVA;Serv.Efetivo;Secretaria M de Planejamento e Desenv Urbano;Geral;9321.04
## 000018;Ativo;07/04/1987 00:00:00;;AGENTE DE SERVICOS PUBLICOS;CHEFE DA DIVISAO DE ARQUITETURA;Serv.Efetiv.Comiss.;Secretaria M de Planejamento e Desenv Urbano;Geral;4778.34
## 000029;Ativo;26/09/1988 00:00:00;;PROF EDUC BASICA IV;PROF EDUC BASICA IV;Serv.Efetivo;Secretaria de Educacao;Fundeb;6620.14
## 000038;Ativo;09/09/1986 00:00:00;;AGENTE DE SERVICOS PUBLICOS;AGENTE DE SERVICOS PUBLICOS;Serv.Efetivo;Secretaria Municipal de Obras e Servicos Publicos;Geral;4153.26
Conclusão
Evitando fazer inferências, demonstramos algumas funcionalidades de jq que, aliadas a utilitários de linha de comando clássicas e modernas, se transformam em ferramentas eficientes para manipulação de dados json.
Referências:
1) Dolan, Stephen. (2022). jq: lightweight and flexible
command-line JSON processor. https://stedolan.github.io/jq/
2) Groskopf, Christopher. (2016). csvkit: suite of command-line
tools for working with CSV format. https://csvkit.readthedocs.io/en/latest/index.html
3) Janssens, J. (2015). Data Science at the Command Line.
4) kojix2 (2020). YouPlot : A command line tool for Unicode
Plotting. https://dev.to/kojix2/youplot-42d9
5) Robbins, A. & Beebe, H.F. (2008). Classic Shell
Scripting.