Wie analysiert man JSON mit Shell-Skripten in Linux?

Wie analysiert man JSON mit Shell-Skripten in Linux?

Ich habe eine JSON-Ausgabe, aus der ich in Linux einige Parameter extrahieren muss.

Dies ist die JSON-Ausgabe:

{
        "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
            }
        ]
    }

Ich möchte eine Datei schreiben, die Überschriften wie Instanz-ID, Tags wie Name, Kostenstelle, Eigentümer und darunter bestimmte Werte aus der JSON-Ausgabe enthält. Die hier angegebene Ausgabe ist nur ein Beispiel.

Wie kann ich das mit sedund machen awk?

Erwartete Ausgabe :

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

Antwort1

Die Verfügbarkeit von Parsern in nahezu jeder Programmiersprache ist einer der Vorteile von JSON als Datenaustauschformat.

Anstatt zu versuchen, einen JSON-Parser zu implementieren, sind Sie wahrscheinlich besser dran, wenn Sie entweder ein für die JSON-Analyse entwickeltes Tool verwenden, wie z. B.jqoder eine allgemeine Skriptsprache, die über eine JSON-Bibliothek verfügt.

Mit jq können Sie beispielsweise die ImageID aus dem ersten Element des Instances-Arrays wie folgt extrahieren:

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

Alternativ können Sie dieselben Informationen auch mit der JSON-Bibliothek von Ruby erhalten:

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

Ich werde nicht alle Ihre überarbeiteten Fragen und Kommentare beantworten, aber das Folgende reicht hoffentlich für den Anfang aus.

Angenommen, Sie hätten ein Ruby-Skript, das von STDIN lesen und die zweite Zeile in Ihrem Beispiel output[0] ausgeben könnte. Das Skript könnte etwa so aussehen:

#!/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}"

Wie könnten Sie ein solches Skript verwenden, um Ihr gesamtes Ziel zu erreichen? Nehmen wir an, Sie hätten bereits Folgendes:

  • ein Befehl zum Auflisten aller Ihrer Instanzen
  • ein Befehl, um den obigen JSON-Code für jede Instanz auf Ihrer Liste abzurufen und an STDOU auszugeben

Eine Möglichkeit wäre, Ihre Shell zu verwenden, um diese Tools zu kombinieren:

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

Nun, vielleicht haben Sie einen einzelnen Befehl, der Ihnen einen JSON-Blob für alle Instanzen mit mehreren Elementen in diesem „Instances“-Array gibt. Nun, wenn das der Fall ist, müssen Sie das Skript nur ein wenig ändern, um durch das Array zu iterieren, anstatt einfach das erste Element zu verwenden.

Letztendlich ist die Lösung dieses Problems die gleiche wie die Lösung vieler anderer Probleme in Unix. Zerlegen Sie es in einfachere Probleme. Suchen oder schreiben Sie Tools, um das einfachere Problem zu lösen. Kombinieren Sie diese Tools mit Ihrer Shell oder anderen Betriebssystemfunktionen.

[0] Beachten Sie, dass ich keine Ahnung habe, woher Sie das Kostenzentrum haben, also habe ich es einfach erfunden.

Antwort2

Sie können das folgende Python-Skript verwenden, um diese Daten zu analysieren. Nehmen wir an, Sie haben JSON-Daten aus Arrays in Dateien array1.jsonwie array2.jsonusw.

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()

Und dann führen Sie einfach aus:

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

Ich habe in Ihren Daten keine Kosten gesehen, deshalb habe ich diese nicht einbezogen.

Gemäß der Diskussion in den Kommentaren habe ich das Skript parse.py aktualisiert:

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"] 

Sie können versuchen, den folgenden Befehl auszuführen:

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

Antwort3

Andere haben allgemeine Antworten auf Ihre Frage gegeben, die gute Möglichkeiten zum Parsen von JSON demonstrieren. Ich suchte jedoch wie Sie nach einer Möglichkeit, eine AWS-Instanz-ID mit einem Kerntool wie awk oder sed zu extrahieren, ohne von anderen Paketen abhängig zu sein. Um dies zu erreichen, können Sie das Argument „--output=text“ an Ihren AWS-Befehl übergeben, der Ihnen eine von awk analysierbare Zeichenfolge gibt. Damit können Sie die Instanz-ID einfach mit etwas wie dem Folgenden abrufen …

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

Antwort4

Wenn dies auf den oben angegebenen AWS-Anwendungsfall beschränkt ist, sollten Sie die Flags --query und --output für Ihren CLI-API-Aufruf verwenden.

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

verwandte Informationen