Análise JSON no shell

11

Como posso analisar a saída JSON no shell?

Por exemplo, o Amazon Web Services fornece uma CLI para recuperar o status de suas instâncias:

$ aws ec2 describe-instances <my_instance_id>

Mas o comando retorna uma sequência JSON. A saída desse comando se parece com isso:

$ aws ec2 describe-instances x12345
{
    "Reservations" :
     {  
            "OwnerId": "1345345"
            "Groups": [], 
            "SecurityGroups": [
               {
                  "Foo" : "yes"
                  "Bar" : "no
               }
             ]
     }
}

Existe algum shells embutido que possa ser usado para analisar a saída JSON?

Por exemplo, eu gostaria de capturar em uma variável de shell FOOo seguinte output["Reservations"]["SecurityGroups"][0]{"Foo"}.

Caso isso ajude, estou especificamente interessado em soluções que poderiam funcionar com o Zsh.

Amelio Vazquez-Reina
fonte
2
Você normalmente usaria uma ferramenta, como jshon .
precisa saber é o seguinte
1
Use --output textse você deseja analisar no shell sem usar ferramentas externas como jshon.
Jordanm # 7/14
1
@jasonwryan - Tendo ouvido falar apenas jshonpela primeira vez, segui seu link. Depois de ler isso, só posso dizer que fiquei muito satisfeito por ter ouvido e instalado por acaso jqprimeiro. Eu acho que você gostaria de ouvir sobre isso também, se ainda não o fez - não se incomoda com todas essas opções de linha de comando e pode fazer suas próprias expressões regulares - até permite que você declare funções e variáveis, se desejar. Veja a resposta aqui sobre isso, se você estiver interessado.
mikeserv

Respostas:

10

Pelo que entendi, você está procurando o valor de "Foo". Isso é realmente fácil de fazer com a ferramenta de linha de comando do shell jq. É algo sedque implementa seu próprio tipo de linguagem analisadora. Dado o seu exemplo:

json='
{
    "Reservations" :
     {  
            "OwnerId" : "1345345",
            "Groups" :  [],
            "SecurityGroups" : [
               {
                  "Foo" : "yes",
                  "Bar" : "no"
               }
             ]
     }
}'

jqpode ser yestão simples quanto:

printf %s "$json" |
jq '.[].SecurityGroups[0].Foo?'                                                

RESULTADO

"yes"

Você pode percorrer uma lista de hash ou dicionário de objeto usando a .dotnotação, e as matrizes indexadas podem ser indexadas de maneira mais simples, com, como você provavelmente já adivinhou, índices numéricos, com 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. Pode ser mais fácil entender dessa maneira:

printf %s "$json" | jq '.[][]'

... que divide todos os valores para os itens de segundo nível no hash e me deixa ...

"1345345"
[]
[
  {
    "Foo": "yes",
    "Bar": "no"
  }
]

Isso apenas arranha a superfície com relação aos jqrecursos. É uma ferramenta imensamente poderosa para serializar dados no shell, é compilada em um único binário executável no estilo clássico do Unix, provavelmente está disponível via gerenciador de pacotes para sua distribuição e está muito bem documentada. Por favor, visite seu git-page e 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 o contrário e usar a .dotnotação para quebrar todos os valores em todos os ní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 jqoferecidos para os vários tipos de nós.

mikeserv
fonte
10

Esta é uma resposta ao seu objetivo, mas não à sua pergunta. Isso significa que você pode atingir seu objetivo sem usar um analisador JSON.

O AWS cli util tem a capacidade de gerar apenas campos de seleção usando o --queryargumento Isso está documentado aqui .

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
Patrick
fonte
1
Obrigado! Isso é muito útil. Estou aceitando @mikeserv principalmente para servir a comunidade com a resposta para a pergunta, mas a resposta é o que eu vou estar usando
Amelio Vazquez-Reina
Isso é muito útil! Muito obrigado!!
MD Sayem Ahmed