![Como analisar JSON com shell script no Linux?](https://rvso.com/image/52096/Como%20analisar%20JSON%20com%20shell%20script%20no%20Linux%3F.png)
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 sed
e 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.json
e array2.json
assim 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