2016-12-14 7 views
4

Ich muss die Ausgabe von lsblk analysieren. Da ich das in einem Skript mache, brauche ich die Ausgabe in einem standardisierten Format. Daher habe ich das JSON-Format als Ausgabe gewählt. Hier ist der Befehl mit einigen Beispielausgabe:Parsing JSON-Format mit jq

# lsblk -o NAME,MOUNTPOINT -J 
{ 
    "blockdevices": [ 
     {"name": "sda", "mountpoint": null, 
     "children": [ 
      {"name": "sda1", "mountpoint": "/sda1/mountpoint"}, 
      {"name": "sda2", "mountpoint": null, 
       "children": [ 
        {"name": "sda2_mapper", "mountpoint": "/sda2/mountpoint"} 
       ] 
      }, 
      {"name": "sda3", "mountpoint": null}, 
      {"name": "sda4", "mountpoint": null} 
     ] 
     }, 
     {"name": "sdb", "mountpoint": null, 
     "children": [ 
      {"name": "sdb1", "mountpoint": "/sdb1/mountpoint"}, 
      {"name": "sdb2", "mountpoint": null} 
     ] 
     }, 
     {"name": "sdc", "mountpoint": null} 
    ] 
} 

Ich möchte die Namen aller innersten Knoten extrahieren, das heißt, den Namen aller Knoten, die keine Kinder. Die gewünschte Ausgabe für das obige Beispiel wäre:

sda1 
sda2_mapper 
sda3 
sda4 
sdb1 
sdb2 
sdc 

Mein Werkzeug der Wahl ist jq, die ich erst vor kurzem entdeckt. Ich habe versucht

# jq '.blockdevices[].children[]?.name?' 

Aber das filtert nur die erste Ebene der Namen. Ich versuchte auch mit

# jq 'recurse(.name?)' 

, aber das gibt die gesamte Datei zurück.

Gibt es eine Möglichkeit, nur Knoten zurückzugeben, die keine untergeordneten Elemente haben, unabhängig davon, wie tief sie verschachtelt sind?

PS: Ich bin in der Lage, die Anforderung in bash oder awk zu implementieren. Ich würde jedoch eine Lösung mit einem Werkzeug wie jq bevorzugen, deren spezieller Zweck ist, JSON-Dateien zu parsen.

Antwort

1

Ich glaube nicht, das ist der einfachste Weg, es zu tun, aber es scheint zu funktionieren:

$ jq -r '.blockdevices[] | .. | objects | select(has("children")|not)| .name' tmp.json 
sda1 
sda2_mapper 
sda3 
sda4 
sdb1 
sdb2 
sdc 

Es rekursiv jeden Wert in der JSON gefunden ausgibt, zunächst etwas Ausfiltern, die kein Objekt , dann jedes Objekt, das einen children Schlüssel hat. Schließlich können Sie den Wert name von jedem verbleibenden Objekt auswählen.

+0

Ich habe eine kurze Follow-up-Frage. Wenn ich die Namen in einem Array aufnehme und die Mountpoints anschließend aufrufen, haben die Mountpoints den gleichen Index wie der entsprechende Name, richtig? Der Befehl wird die Reihenfolge der ursprünglichen Ausgabe nicht ändern, wenn ich keine Option wie '--sort-keys' hinzufüge, richtig? – nautical

+0

Korrigieren. Der Filter, der dem '.name'-Filter vorangestellt ist, erzeugt die Wörterbücher, die sowohl die' name'- als auch die 'mountpoint'-Schlüssel enthalten. – chepner

0

Mit Ihrem JSON-Eingang, den folgenden Befehl ein:

jq '.. | scalars' 

emittiert die "Blätter" ab:

"sda" 
"sda1" 
"/sda1/mountpoint" 

Verwenden Sie die -r (Rohausgangssignal) die Anführungszeichen aus Strings abzustreifen .