J'ai une sortie JSON à partir de laquelle j'ai besoin d'extraire quelques paramètres sous Linux.
Voici la sortie 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
}
]
}
Je veux écrire un fichier contenant un en-tête comme l'ID d'instance, une balise comme le nom, le centre de coûts, le propriétaire. et en dessous de certaines valeurs de la sortie JSON. La sortie donnée ici n'est qu'un exemple.
Comment puis-je faire cela en utilisant sed
et awk
?
Sortie attendue:
Instance id Name cost centre Owner
i-1234576 RDS_Machine (us-east-1c) 1234 Jyoti
La disponibilité des analyseurs dans presque tous les langages de programmation est l'un des avantages de JSON en tant que format d'échange de données.
Plutôt que d'essayer d'implémenter un analyseur JSON, vous feriez probablement mieux d'utiliser soit un outil conçu pour l'analyse JSON tel que jq ou un langage de script à usage général qui possède une bibliothèque JSON.
Par exemple, en utilisant jq, vous pouvez extraire l'ImageID du premier élément du tableau Instances comme suit:
jq '.Instances[0].ImageId' test.json
Alternativement, pour obtenir les mêmes informations en utilisant la bibliothèque JSON de Ruby:
Ruby -rjson -e 'j = JSON.parse(File.read("test.json")); puts j["Instances"][0]["ImageId"]'
Je ne répondrai pas à toutes vos questions et commentaires révisés, mais nous espérons que ce qui suit est suffisant pour vous aider à démarrer.
Supposons que vous disposiez d'un script Ruby qui pourrait lire un depuis STDIN et afficher la deuxième ligne dans votre exemple de sortie [0]. Ce script pourrait ressembler à quelque chose comme:
#!/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}"
Comment pourriez-vous utiliser un tel script pour atteindre l'ensemble de votre objectif? Eh bien, supposons que vous disposiez déjà des éléments suivants:
Une façon serait d'utiliser votre Shell pour combiner ces outils:
echo -e "Instance id\tName\tcost centre\tOwner"
for instance in $(list-instances); do
get-json-for-instance $instance | ./ugly-Ruby-scriptrb
done
Maintenant, peut-être que vous avez une seule commande qui vous donne un blob json pour toutes les instances avec plus d'éléments dans ce tableau "Instances". Eh bien, si c'est le cas, vous aurez juste besoin de modifier un peu le script pour parcourir le tableau plutôt que d'utiliser simplement le premier élément.
En fin de compte, la façon de résoudre ce problème est la façon de résoudre de nombreux problèmes sous Unix. Décomposez-le en problèmes plus faciles. Trouvez ou écrivez des outils pour résoudre le problème le plus facile. Combinez ces outils avec votre Shell ou d'autres fonctionnalités du système d'exploitation.
[0] Notez que je n'ai aucune idée d'où vous obtenez le centre de coûts, donc je viens de l'inventer.
Vous pouvez utiliser le script python suivant pour analyser ces données. Supposons que vous disposez de données JSON provenant de tableaux dans des fichiers comme 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()
Et puis lancez:
$ for x in `ls *.json`; do python parse.py $x; done
InstanceId - Name - Owner
i-1234576 - RDS_Machine (us-east-1c) - Jyoti Bhanot
Je n'ai pas vu le coût dans vos données, c'est pourquoi je ne l'ai pas inclus.
Selon la discussion dans les commentaires, j'ai mis à jour le 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"]
Vous pouvez essayer d'exécuter la commande suivante:
#ec2-describe-instance <instance> | python parse.py
D'autres ont fourni des réponses générales à votre question qui démontrent de bonnes façons d'analyser json mais moi, comme vous, je cherchais un moyen d'extraire un identifiant d'instance aws en utilisant un outil de base comme awk ou sed sans dépendre d'autres packages. Pour ce faire, vous pouvez passer l'argument "--output = text" à votre commande aws qui vous donnera une chaîne analysable awk. Avec cela, vous pouvez simplement obtenir l'ID d'instance en utilisant quelque chose comme ce qui suit ...
aws ec2 run-instances --output text | awk -F"\t" '$1=="INSTANCES" {print $8}'
Le code jq suivant:
.Instances[] | (.Tags | map(.value=.Value | .key=.Key) | from_entries) as $tags | "\(.InstanceId) | \($tags.Name) | \($tags["cost.centre"]) | \($tags.Owner)"
utilisé comme:
json_producer | jq -r '<jq code...>'
produirait:
i-1234576 | RDS_Machine (us-east-1c) | 1234 | Jyoti Bhanot
Quelques conseils pour comprendre le code:
from_entries
prend un tableau d'objets comme {key:a, value:b}
et le transforme en objet avec les paires clé/valeur correspondantes ({a: b}
);Key
et Value
du tableau Tags
ont dû être converties en minuscules;Pour plus de détails, allez voir le tutoriel et le manuel de jq sur https://stedolan.github.io/jq/
Jshon est disponible en plusieurs distributions:
$ echo your_JSON|jshon -e Instances -a -e InstanceId -u -p -e Tags -a -e Key -u -p -e Value -u
i-1234576
Description
Server for testing RDS feature in us-east-1c AZ
Name
RDS_Machine (us-east-1c)
cost.centre
1234
Owner
Jyoti Bhanot
Mauvaise explication: -e uu
va extraire l'objet uu
, -a
rendra le tableau utilisable (je ne suis pas sûr d'avoir correctement formulé celui-ci mais de toute façon…), -u
décodera la chaîne, -p
reviendra à l'élément précédent (semble que -i N
, N étant un nombre quelconque, a le même effet).
Selon votre cas, la sortie peut nécessiter un post-traitement (comme le vôtre, comme vous pouvez le voir).
Jshon
ne semble pas robuste contre les malformations JSON, cependant (vos "Tags" avec des virgules avant le crochet bouclé fermera une erreur).
Quelqu'un a mentionné jsawk dans un autre fil, mais je ne l'ai pas testé.
Si cela se limite au cas d'utilisation AWS fourni ci-dessus, vous devez utiliser les indicateurs --query et --output pour votre appel API CLI
http://docs.aws.Amazon.com/cli/latest/userguide/controlling-output.html
Voici une suggestion pour une ligne:
pr -mt \
<(grep -o ".*: .*," in.json | grep -iw InstanceId | cut -d: -f2) \
<(grep -o ".*: .*," in.json | grep -iw Value | cut -d: -f2) \
<(grep -o ".*: .*," in.json | grep -iw Key | cut -d: -f2)
Pas parfait, mais ça marcherait si vous le peaufiniez un peu.
Il utilise essentiellement pr
pour imprimer chaque résultat d'ensemble par colonne. Chaque jeu de résultats est renvoyé par substitution de processus qui analyse le fichier JSON et renvoie des valeurs en fonction de la clé.
Cela fonctionne de la même manière que décrit dans: Étant donné le contenu de la valeur-clé, comment puis-je regrouper les valeurs par clé et trier par valeur?
Jetez un oeil à jtc
outil cli:
il permet d'extraire facilement les informations requises de votre json (en supposant que ce soit dans file.json
, btw, votre JSON doit être corrigé, il y a quelques virgules supplémentaires):
bash $ cat file.json | jtc -x '<InstanceId>l+0[-1]' -y '[InstanceId]' -y "[Key]:<Name>[-1][Value]" -y "[Key]:<cost.centre>[-1][Value]" -y "[Key]:<Owner>[-1][Value]" | sed 's/"/\\"/g' | xargs -L4 echo
"i-1234576" "RDS_Machine (us-east-1c)" "1234" "Jyoti Bhanot"
bash $