![¿Cómo analizar JSON con scripts de shell en Linux?](https://rvso.com/image/52096/%C2%BFC%C3%B3mo%20analizar%20JSON%20con%20scripts%20de%20shell%20en%20Linux%3F.png)
Tengo una salida JSON de la cual necesito extraer algunos parámetros en Linux.
Esta es la salida 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
}
]
}
Quiero escribir un archivo que contenga un encabezado como identificación de instancia, etiqueta como nombre, centro de costos y propietario. y debajo de eso ciertos valores de la salida JSON. El resultado que se proporciona aquí es solo un ejemplo.
¿Cómo puedo hacer eso usando sed
y awk
?
Rendimiento esperado :
Instance id Name cost centre Owner
i-1234576 RDS_Machine (us-east-1c) 1234 Jyoti
Respuesta1
La disponibilidad de analizadores en casi todos los lenguajes de programación es una de las ventajas de JSON como formato de intercambio de datos.
En lugar de intentar implementar un analizador JSON, probablemente sea mejor utilizar una herramienta creada para el análisis JSON, comojqo un lenguaje de script de propósito general que tenga una biblioteca JSON.
Por ejemplo, usando jq, puede extraer el ImageID del primer elemento de la matriz Instancias de la siguiente manera:
jq '.Instances[0].ImageId' test.json
Alternativamente, para obtener la misma información usando la biblioteca JSON de Ruby:
ruby -rjson -e 'j = JSON.parse(File.read("test.json")); puts j["Instances"][0]["ImageId"]'
No responderé a todas sus preguntas y comentarios revisados, pero espero que lo siguiente sea suficiente para comenzar.
Supongamos que tiene un script Ruby que puede leer desde STDIN y generar la segunda línea en su salida de ejemplo [0]. Ese script podría verse así:
#!/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}"
¿Cómo podrías utilizar un guión así para lograr tu objetivo? Bueno, supongamos que ya tienes lo siguiente:
- un comando para enumerar todas sus instancias
- un comando para obtener el json anterior para cualquier instancia de su lista y enviarlo a STDOU
Una forma sería utilizar su shell para combinar estas herramientas:
echo -e "Instance id\tName\tcost centre\tOwner"
for instance in $(list-instances); do
get-json-for-instance $instance | ./ugly-ruby-scriptrb
done
Ahora, tal vez tenga un único comando que le brinde un blob json para todas las instancias con más elementos en esa matriz "Instancias". Bueno, si ese es el caso, sólo necesitarás modificar un poco el script para iterar a través de la matriz en lugar de simplemente usar el primer elemento.
Al final, la forma de resolver este problema es la forma de resolver muchos problemas en Unix. Divídalo en problemas más fáciles. Encuentre o escriba herramientas para resolver el problema más fácil. Combine esas herramientas con su shell u otras características del sistema operativo.
[0] Tenga en cuenta que no tengo idea de dónde obtiene el centro de costos, así que lo inventé.
Respuesta2
Puede utilizar el siguiente script de Python para analizar esos datos. Supongamos que tiene datos JSON de matrices en archivos como array1.json
, array2.json
etc.
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()
Y luego simplemente ejecuta:
$ for x in `ls *.json`; do python parse.py $x; done
InstanceId - Name - Owner
i-1234576 - RDS_Machine (us-east-1c) - Jyoti Bhanot
No he visto el costo en sus datos, por eso no lo incluí.
Según la discusión en los comentarios, he actualizado el 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"]
Puedes intentar ejecutar el siguiente comando:
#ec2-describe-instance <instance> | python parse.py
Respuesta3
Otros han proporcionado respuestas generales a su pregunta que demuestran buenas formas de analizar json; sin embargo, yo, como usted, estaba buscando una manera de extraer una identificación de instancia de AWS utilizando una herramienta central como awk o sed sin depender de otros paquetes. Para lograr esto, puede pasar el argumento "--output=text" a su comando aws, lo que le dará una cadena analizable awk. Con eso, simplemente puede obtener el ID de la instancia usando algo como lo siguiente...
aws ec2 run-instances --output text | awk -F"\t" '$1=="INSTANCES" {print $8}'
Respuesta4
Si esto se limita al caso de uso de AWS proporcionado anteriormente, debe usar los indicadores --query y --output para su llamada API CLI
http://docs.aws.amazon.com/cli/latest/userguide/controlling-output.html