JSON-Analyse auf der Shell

10

Wie kann ich die JSON-Ausgabe in der Shell analysieren?

Beispielsweise bietet Amazon Web Services eine CLI zum Abrufen des Status Ihrer Instanzen:

$ aws ec2 describe-instances <my_instance_id>

Der Befehl gibt jedoch eine JSON-Zeichenfolge zurück. Die Ausgabe dieses Befehls sieht folgendermaßen aus:

$ aws ec2 describe-instances x12345
{
    "Reservations" :
     {  
            "OwnerId": "1345345"
            "Groups": [], 
            "SecurityGroups": [
               {
                  "Foo" : "yes"
                  "Bar" : "no
               }
             ]
     }
}

Gibt es integrierte Shells, mit denen die JSON-Ausgabe analysiert werden kann?

Zum Beispiel möchte ich in einer Shell-Variablen FOOFolgendes erfassen output["Reservations"]["SecurityGroups"][0]{"Foo"}.

Falls es hilft, bin ich speziell an Lösungen interessiert, die von Zsh aus funktionieren könnten.

Amelio Vazquez-Reina
quelle
2
Normalerweise verwenden Sie ein Tool wie jshon .
Jasonwryan
1
Verwenden --output textSie diese Option, wenn Sie die Shell analysieren möchten, ohne externe Tools wie verwenden zu müssen jshon.
Jordan
1
@jasonwryan - Nachdem ich erst jetzt jshonzum ersten Mal davon gehört habe, bin ich Ihrem Link gefolgt. Nachdem ich das gelesen habe, kann ich nur sagen, dass ich sehr erfreut war, dass ich zufällig zuerst davon gehört und es installiert habe jq. Ich denke, Sie möchten vielleicht auch davon hören, wenn Sie es noch nicht getan haben - es stört nicht alle diese Befehlszeilenschalter und kann seine eigenen regulären Ausdrücke ausführen - es ermöglicht Ihnen sogar, Funktionen und Variablen zu deklarieren, wenn Sie dies wünschen. Sehen Sie die Antwort hier darüber, wenn Sie interessiert sind.
Mikesserv

Antworten:

9

So wie ich es verstehe, suchen Sie nach dem Wert von "Foo". Dies ist mit dem Shell-Befehlszeilentool sehr einfach jq. Es ist so ähnlich, seddass es eine eigene Art von Parser-Sprache implementiert. Anhand Ihres Beispiels:

json='
{
    "Reservations" :
     {  
            "OwnerId" : "1345345",
            "Groups" :  [],
            "SecurityGroups" : [
               {
                  "Foo" : "yes",
                  "Bar" : "no"
               }
             ]
     }
}'

jqkann yesso einfach werden wie:

printf %s "$json" |
jq '.[].SecurityGroups[0].Foo?'                                                

AUSGABE

"yes"

Sie können mithilfe der .dotNotation durch einen Objekt-Hash oder eine Wörterbuchliste gehen , und indizierte Arrays können einfacher mit numerischen Indizes in eckigen Klammern indiziert werden, wie Sie wahrscheinlich vermutet haben. Im obigen Befehl verwende ich das leere Indexformular, um anzugeben, dass alle iterierbaren Elemente dieser Ebene erweitert werden sollen. Das kann auf diese Weise einfacher zu verstehen sein:

printf %s "$json" | jq '.[][]'

... was alle Werte für die Elemente der zweiten Ebene im Hash aufschlüsselt und mich ...

"1345345"
[]
[
  {
    "Foo": "yes",
    "Bar": "no"
  }
]

Dies kratzt kaum an der Oberfläche in Bezug auf jqdie Fähigkeiten. Es ist ein immens leistungsfähiges Tool zum Serialisieren von Daten in der Shell, es wird zu einer einzigen ausführbaren Binärdatei im klassischen Unix-Stil kompiliert, es ist sehr wahrscheinlich über den Paketmanager für Ihre Distribution verfügbar und es ist sehr gut dokumentiert. Bitte besuchen Sie die gitSeite und überzeugen Sie sich selbst.

Übrigens könnte eine andere Möglichkeit, geschichtete Daten in Angriff zu nehmen json- zumindest um eine Vorstellung davon zu bekommen, mit was Sie arbeiten - darin bestehen, in die andere Richtung zu gehen und die .dotNotation zu verwenden, um alle Werte auf allen Ebenen aufzuteilen, z.

printf %s "$json" | jq '..'

{
  "Reservations": {
    "OwnerId": "1345345",
    "Groups": [],
    "SecurityGroups": [
      {
        "Foo": "yes",
        "Bar": "no"
      }
    ]
  }
}
{
  "OwnerId": "1345345",
  "Groups": [],
  "SecurityGroups": [
    {
      "Foo": "yes",
      "Bar": "no"
    }
  ]
}
"1345345"
[]
[
  {
    "Foo": "yes",
    "Bar": "no"
  }
]
{
  "Foo": "yes",
  "Bar": "no"
}
"yes"
"no"

Aber weitaus besser wäre es wahrscheinlich, nur eine der vielen Erkennungs- oder Suchmethoden zu verwenden, jqdie für die verschiedenen Knotentypen angeboten werden.

mikeserv
quelle
10

Dies ist eine Antwort auf Ihr Ziel, aber nicht auf Ihre Frage. Das heißt, Sie können Ihr Ziel erreichen, ohne einen JSON-Parser zu verwenden.

Das AWS cli util kann nur ausgewählte Felder mit dem --queryArgument ausgeben . Dies ist hier dokumentiert .

Zum Beispiel:

$ aws ec2 describe-instances \
  --query 'Reservations[0].Instances[0].SecurityGroups[0].GroupName' \
  --instance-id i-6b272337 \
  --output text
mongodb

Sie können sogar mehrere Felder auswählen, wenn Sie möchten:

$ aws ec2 describe-instances \
  --query 'Reservations[0].Instances[0].SecurityGroups[0].[GroupName,GroupId]' \
  --instance-id i-6b272337 \
  --output text
mongodb sg-710ffa14

Sie können auch mehrere übereinstimmende Strukturen anzeigen:

$ aws ec2 describe-instances \
  --query 'Reservations[0].Instances[0].SecurityGroups[*].[GroupName,GroupId]' \
  --instance-id i-6b272337 \
  --output text
mongodb sg-710ffa14
default sg-a0243bcc
Patrick
quelle
1
Vielen Dank! Das ist sehr hilfreich. Ich akzeptiere @mikeserv hauptsächlich, um der Community mit der Antwort auf die Frage zu dienen, aber Ihre Antwort ist die, die ich verwenden werde
Amelio Vazquez-Reina
Das ist sehr hilfreich! Vielen Dank!!
MD Sayem Ahmed