
Como posso analisar a saída JSON no shell?
Por exemplo, a Amazon Web Services fornece uma CLI para recuperar o status das suas instâncias:
$ aws ec2 describe-instances <my_instance_id>
Mas o comando retorna uma string JSON. A saída desse comando é semelhante a esta:
$ aws ec2 describe-instances x12345
{
"Reservations" :
{
"OwnerId": "1345345"
"Groups": [],
"SecurityGroups": [
{
"Foo" : "yes"
"Bar" : "no
}
]
}
}
Existem shells integrados que podem ser usados para analisar a saída JSON?
Por exemplo, eu gostaria de capturar em uma variável shell FOO
o seguinte output["Reservations"]["SecurityGroups"][0]{"Foo"}
.
Caso ajude, estou especificamente interessado em soluções que possam funcionar no Zsh.
Responder1
Pelo que entendi, você está procurando o valor de "Foo". Isso érealmentefácil de fazer com a ferramenta de linha de comando do shell jq
. É algo parecido sed
porque implementa seu próprio tipo de linguagem de analisador. Dado o seu exemplo:
json='
{
"Reservations" :
{
"OwnerId" : "1345345",
"Groups" : [],
"SecurityGroups" : [
{
"Foo" : "yes",
"Bar" : "no"
}
]
}
}'
jq
pode ser yes
tão simples quanto:
printf %s "$json" |
jq '.[].SecurityGroups[0].Foo?'
SAÍDA
"yes"
Você pode percorrer um hash de objeto ou uma lista de dicionário usando a .dot
notação, e matrizes indexadas podem ser indexadas de forma mais simples, com, como você provavelmente já adivinhou, índices numéricos entre colchetes. No comando acima, uso o formulário de índice vazio para indicar que desejo que todos os itens iteráveis desse nível sejam expandidos. Isso pode ser mais fácil de entender desta forma:
printf %s "$json" | jq '.[][]'
... que divide todos os valores dos itens de segundo nível no hash e me leva...
"1345345"
[]
[
{
"Foo": "yes",
"Bar": "no"
}
]
Isso mal arranha a superfície no que diz respeito às jq
capacidades do . É uma ferramenta imensamente poderosa para serializar dados no shell, compila em um único binário executável no estilo Unix clássico, provavelmente está disponível através do gerenciador de pacotes para sua distribuição e está muito bem documentado. Por favor visite o seugit
-páginae veja por si mesmo.
A propósito, outra maneira de lidar com dados em camadas json
- pelo menos para ter uma ideia do que você está trabalhando - pode ser seguir o outro caminho e usar a .dot
notação para dividirtodosvalores emtodosníveis como:
printf %s "$json" | jq '..'
{
"Reservations": {
"OwnerId": "1345345",
"Groups": [],
"SecurityGroups": [
{
"Foo": "yes",
"Bar": "no"
}
]
}
}
{
"OwnerId": "1345345",
"Groups": [],
"SecurityGroups": [
{
"Foo": "yes",
"Bar": "no"
}
]
}
"1345345"
[]
[
{
"Foo": "yes",
"Bar": "no"
}
]
{
"Foo": "yes",
"Bar": "no"
}
"yes"
"no"
Mas muito melhor, provavelmente, seria apenas usar um dos muitos métodos de descoberta ou pesquisa oferecidos jq
para os vários tipos de nós.
Responder2
Esta é uma resposta ao seu objetivo, mas não à sua pergunta. O que significa que você pode atingir seu objetivo sem usar um analisador JSON.
O utilitário CLI da AWS tem a capacidade de gerar apenas campos selecionados usando o --query
argumento. Isto está documentadoaqui.
Por exemplo:
$ aws ec2 describe-instances \
--query 'Reservations[0].Instances[0].SecurityGroups[0].GroupName' \
--instance-id i-6b272337 \
--output text
mongodb
Você pode até selecionar vários campos se desejar:
$ aws ec2 describe-instances \
--query 'Reservations[0].Instances[0].SecurityGroups[0].[GroupName,GroupId]' \
--instance-id i-6b272337 \
--output text
mongodb sg-710ffa14
E você também pode mostrar várias estruturas correspondentes:
$ aws ec2 describe-instances \
--query 'Reservations[0].Instances[0].SecurityGroups[*].[GroupName,GroupId]' \
--instance-id i-6b272337 \
--output text
mongodb sg-710ffa14
default sg-a0243bcc