Como analisar JSON com shell script no Linux?

Como analisar JSON com shell script no Linux?

Tenho uma saída JSON da qual preciso extrair alguns parâmetros no Linux.

Esta é a saída JSON:

{
        "OwnerId": "121456789127",
        "ReservationId": "r-48465168",
        "Groups": [],
        "Instances": [
            {
                "Monitoring": {
                    "State": "disabled"
                },
                "PublicDnsName": null,
                "RootDeviceType": "ebs",
                "State": {
                    "Code": 16,
                    "Name": "running"
                },
                "EbsOptimized": false,
                "LaunchTime": "2014-03-19T09:16:56.000Z",
                "PrivateIpAddress": "10.250.171.248",
                "ProductCodes": [
                    {
                        "ProductCodeId": "aacglxeowvn5hy8sznltowyqe",
                        "ProductCodeType": "marketplace"
                    }
                ],
                "VpcId": "vpc-86bab0e4",
                "StateTransitionReason": null,
                "InstanceId": "i-1234576",
                "ImageId": "ami-b7f6c5de",
                "PrivateDnsName": "ip-10-120-134-248.ec2.internal",
                "KeyName": "Test_Virginia",
                "SecurityGroups": [
                    {
                        "GroupName": "Test",
                        "GroupId": "sg-12345b"
                    }
                ],
                "ClientToken": "VYeFw1395220615808",
                "SubnetId": "subnet-12345314",
                "InstanceType": "t1.micro",
                "NetworkInterfaces": [
                    {
                        "Status": "in-use",
                        "SourceDestCheck": true,
                        "VpcId": "vpc-123456e4",
                        "Description": "Primary network interface",
                        "NetworkInterfaceId": "eni-3619f31d",
                        "PrivateIpAddresses": [
                            {
                                "Primary": true,
                                "PrivateIpAddress": "10.120.134.248"
                            }
                        ],
                        "Attachment": {
                            "Status": "attached",
                            "DeviceIndex": 0,
                            "DeleteOnTermination": true,
                            "AttachmentId": "eni-attach-9210dee8",
                            "AttachTime": "2014-03-19T09:16:56.000Z"
                        },
                        "Groups": [
                            {
                                "GroupName": "Test",
                                "GroupId": "sg-123456cb"
                            }
                        ],
                        "SubnetId": "subnet-31236514",
                        "OwnerId": "109030037527",
                        "PrivateIpAddress": "10.120.134.248"
                    }
                ],
                "SourceDestCheck": true,
                "Placement": {
                    "Tenancy": "default",
                    "GroupName": null,
                    "AvailabilityZone": "us-east-1c"
                },
                "Hypervisor": "xen",
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda",
                        "Ebs": {
                            "Status": "attached",
                            "DeleteOnTermination": false,
                            "VolumeId": "vol-37ff097b",
                            "AttachTime": "2014-03-19T09:17:00.000Z"
                        }
                    }
                ],
                "Architecture": "x86_64",
                "KernelId": "aki-88aa75e1",
                "RootDeviceName": "/dev/sda1",
                "VirtualizationType": "paravirtual",
                "Tags": [
                    {
                        "Value": "Server for testing RDS feature in us-east-1c AZ",
                        "Key": "Description"
                    },
                    {
                        "Value": "RDS_Machine (us-east-1c)",
                        "Key": "Name"
                    },
                    {
                        "Value": "1234",
                        "Key": "cost.centre",
                      },
                    {
                        "Value": "Jyoti Bhanot",
                        "Key": "Owner",
                      }
                ],
                "AmiLaunchIndex": 0
            }
        ]
    }

Quero escrever um arquivo que contenha cabeçalhos como ID da instância, tags como nome, centro de custo, proprietário. e abaixo disso determinados valores da saída JSON. A saída aqui fornecida é apenas um exemplo.

Como posso fazer isso usando sede awk?

Resultado esperado:

 Instance id         Name                           cost centre             Owner
    i-1234576          RDS_Machine (us-east-1c)        1234                   Jyoti

Responder1

A disponibilidade de analisadores em quase todas as linguagens de programação é uma das vantagens do JSON como formato de intercâmbio de dados.

Em vez de tentar implementar um analisador JSON, provavelmente será melhor usar uma ferramenta criada para análise JSON, comojqou uma linguagem de script de uso geral que possui uma biblioteca JSON.

Por exemplo, usando jq, você poderia extrair o ImageID do primeiro item do array Instances da seguinte forma:

jq '.Instances[0].ImageId' test.json

Alternativamente, para obter as mesmas informações usando a biblioteca JSON do Ruby:

ruby -rjson -e 'j = JSON.parse(File.read("test.json")); puts j["Instances"][0]["ImageId"]'

Não responderei a todas as suas perguntas e comentários revisados, mas espero que o seguinte seja suficiente para você começar.

Suponha que você tenha um script Ruby que possa ler a partir de STDIN e gerar a segunda linha em seu exemplo de saída[0]. Esse script pode ser algo como:

#!/usr/bin/env ruby
require 'json'

data = JSON.parse(ARGF.read)
instance_id = data["Instances"][0]["InstanceId"]
name = data["Instances"][0]["Tags"].find {|t| t["Key"] == "Name" }["Value"]
owner = data["Instances"][0]["Tags"].find {|t| t["Key"] == "Owner" }["Value"]
cost_center = data["Instances"][0]["SubnetId"].split("-")[1][0..3]
puts "#{instance_id}\t#{name}\t#{cost_center}\t#{owner}"

Como você poderia usar esse script para atingir todo o seu objetivo? Bem, suponha que você já tenha o seguinte:

  • um comando para listar todas as suas instâncias
  • um comando para obter o json acima para qualquer instância da sua lista e enviá-lo para STDOU

Uma maneira seria usar seu shell para combinar estas ferramentas:

echo -e "Instance id\tName\tcost centre\tOwner"
for instance in $(list-instances); do
    get-json-for-instance $instance | ./ugly-ruby-scriptrb
done

Agora, talvez você tenha um único comando que forneça um blob json para todas as instâncias com mais itens na matriz "Instâncias". Bem, se for esse o caso, você só precisará modificar um pouco o script para iterar pelo array, em vez de simplesmente usar o primeiro item.

No final das contas, a maneira de resolver esse problema é a maneira de resolver muitos problemas no Unix. Divida-o em problemas mais fáceis. Encontre ou escreva ferramentas para resolver o problema mais fácil. Combine essas ferramentas com seu shell ou outros recursos do sistema operacional.

[0] Observe que não tenho ideia de onde você obtém o centro de custo, então acabei de inventar.

Responder2

Você pode usar o seguinte script python para analisar esses dados. Vamos supor que você tenha dados JSON de arrays em arquivos como array1.jsone array2.jsonassim por diante.

import json
import sys
from pprint import pprint

jdata = open(sys.argv[1])

data = json.load(jdata)

print "InstanceId", " - ", "Name", " - ", "Owner"
print data["Instances"][0]["InstanceId"], " - " ,data["Instances"][0]["Tags"][1]["Value"], " - " ,data["Instances"][0]["Tags"][2]["Value"] 

jdata.close()

E então é só executar:

$ for x in `ls *.json`; do python parse.py $x; done
InstanceId  -  Name  -  Owner
i-1234576  -  RDS_Machine (us-east-1c)  -  Jyoti Bhanot

Não vi custo em seus dados, por isso não incluí isso.

De acordo com a discussão nos comentários, atualizei o script parse.py:

import json
import sys
from pprint import pprint

jdata = sys.stdin.read()

data = json.loads(jdata)

print "InstanceId", " - ", "Name", " - ", "Owner"
print data["Instances"][0]["InstanceId"], " - " ,data["Instances"][0]["Tags"][1]["Value"], " - " ,data["Instances"][0]["Tags"][2]["Value"] 

Você pode tentar executar o seguinte comando:

#ec2-describe-instance <instance> | python parse.py

Responder3

Outros forneceram respostas gerais para sua pergunta que demonstram boas maneiras de analisar json, no entanto, eu, como você, estava procurando uma maneira de extrair um ID de instância do aws usando uma ferramenta principal como awk ou sed sem depender de outros pacotes. Para fazer isso, você pode passar o argumento "--output = text" para o comando aws, que fornecerá uma string analisável awk. Com isso você pode simplesmente obter o ID da instância usando algo como o seguinte...

aws ec2 run-instances --output text  | awk -F"\t" '$1=="INSTANCES" {print $8}'

Responder4

Se isso estiver limitado ao caso de uso da AWS fornecido acima, você deverá usar os sinalizadores --query e --output para sua chamada de API CLI

http://docs.aws.amazon.com/cli/latest/userguide/controlling-output.html

informação relacionada