Umgang mit JSON-Abfragesprachen, Teil 3 jq zum Filtern von JSON-Ausgaben nutzen
Angesichts der vielen Einsatzbereiche von JSON ist es nützlich, sich mit gängigen Abfrage-Tools für JSON vertraut zu machen. Mit „jq“ widmen wir uns nach JSON Path und JMSPath dem mächtigsten Tool in Trio, bleiben aber aufgrund der Vielzahl an Möglichkeiten vorerst bei den Basics.

JQ (im Folgenden jq) basiert auf dem Konzept von Filtern, die über einen JSON-Stream arbeiten. Jeder Filter nimmt eine Eingabe entgegen und gibt JSON an die Standardausgabe aus. Dabei gibt es zahlreiche vordefinierte Filter, die Sie verwenden können. Darüber hinaus können Sie solche Filter problemlos mit Pipes kombinieren, um schnell komplexe Operationen und Transformationen auf JSON-Daten erstellen und anwenden zu können.
Zuerst muss jq installiert werden. Zwar verfügen die meisten Programmiersprachen über Bibliotheken oder Module, die das Analysieren von JSON-Daten erlauben, leider gilt das gerade nicht für die Bash. Mit jq dagegen können Sie JSON einfach in der Bash-Shell parsen oder sogar XML in JSON konvertieren. Das Installieren von für die gängigen Linux-Distributionen ist simpel, verwenden Sie bei Ubuntu …
sudo apt-get install jq
… und bei Red Hat/CentOS …
sudo dnf install jq
Es ist auch möglich, die Binärdatei direkt herunterzuladen oder aus den Quellen zu übersetzen. Zum Überprüfen der Installation rufen Sie jq einfach ohne Parameter auf. Schauen wir uns mit dem Identitätsfilter ‚.‘ zunächst den einfachsten Filter von allen an, der übrigens eine der nützlichsten und am häufigsten verwendeten Funktionen von jq ist:
echo '{"auto":{"name":"audi","farbe":"silber","preis":50000}}' | jq '.'
Hier geben Sie einen einfachen JSON-String als Echo zurück und leiten ihn direkt an das jq-Kommando weiter. Dann verwenden Sie den Identitätsfilter ".". Dieser übernimmt die Eingabe übernimmt und gibt sie unverändert als Ausgabe aus, mit der Einschränkung, dass jq die Ausgabe standardmäßig farbig formatiert.
Sie können diesen Filter auch direkt auf eine JSON-Datei anwenden:
jq '.' auto.json
Die Möglichkeit, JSON zu verschönern, ist besonders dann nützlich, wenn Sie Daten von einer API abrufen und die Antwort in einem klaren, lesbaren Format anzeigen möchten, wie das z. B. beim Cloud Computing der Fall ist. Es gibt aber auch zahllose öffentlich zugängliche APIs mit denen Sie experimentieren können. So liefert z. B. …
curl http://api.open-notify.org/iss-now.json | jq '.'
… die aktuelle Position der Internationalen Raumstation ISS.
Rufen Sie doch analog zu unserem Artikel über JMSPath die Lister aller aktuellen virtuellen Maschinen im zuvor authentifizierten Azure-Konto ab:
az vm list | jq
Dabei können Sie auf Eigenschaftswerte zugreifen, indem Sie einen anderen einfachen Filter, den .field-Operator. Verwenden. Um einen Eigenschaftswert zu finden, kombinieren Sie einfach diesen Filter gefolgt vom Eigenschaftsnamen. Testen Sie das anhand unseres einfachen Auto-Datei-Beispiels:
jq ´.auto´ auto.json
Sie können Eigenschaftswerte auch miteinander verketten, womit Sie auf verschachtelte Objekte zugreifen können:
jq '.auto.farbe' auto.json
Wenn Sie mehrere Schlüssel abrufen müssen, können Sie diese durch ein Komma trennen:
jq '.auto.farbe,.auto.preis' auto.json
Enthält eine der Eigenschaften Leerzeichen oder Sonderzeichen, müssen Sie den Eigenschaftsnamen in Anführungszeichen setzen.
Arbeiten mit Arrays
Schauen Sie uns nun an, wie Sie mit Arrays in JSON-Daten arbeiten können. Normalerweise verwenden Sie Arrays, um eine Liste von Elementen darzustellen. Wie bei vielen Programmiersprachen verwendet jq eckige Klammern, um den Anfang und das Ende eines Arrays zu kennzeichnen. Folgendes Beispiel zeigt, wie Sie über ein Array iterieren:
echo '["a","b","c"]' | jq '.[]'
Erstellen Sie nun eine Liste mit Autos als JSON-Dokument:
[
{
"name": "audi",
"farbe": "silber",
"preis": 50000
},
{
"name": "dacia",
"farbe": "braun",
"preis": 10000
},
{
"name": "opel",
"farbe": "weiss",
"preis": 20000
}
]
Hierbei ist jedes Element im Array ein Objekt, das eine Auto darstellt. Nun können Sie z. B. den Namen jedes Autos aus jedem Objekt im Array extrahieren:
jq '.[] | .name' autos.json
Das Kommando iteriert zuerst mit .[] über das gesamte Array. Danach übergibt es jedes Objekt im Array via Pipe (|) an den nächsten Filter im Befehl. Im letzten Schritt wird mit „.name“ das Namensfeld jedes Objekts ausgegeben: Alternativ können Sie mit …
jq '.[].name' autos.json
… auch direkt auf die Eigenschaft für jedes Objekt im Array zugreifen. Und wie bei allen Arrays können Sie auch direkt auf eines der Elemente im Array zugreifen, indem Sie den jeweiligen Index übergeben:
jq '.[2].preis' autos.json
Funktionen nutzen
Eigentlich ist jq viel mehr als ein Filter und verfügt über viele leistungsstarke integrierte Funktionen, mit denen Sie eine Vielzahl nützlicher Operationen ausführen können. Eine dieser praktischen Funktionen für Arrays und Objekte ist die Längenfunktion. Diese können Sie nutzen, um die Länge des Arrays oder die Anzahl der Eigenschaften eines Objekts zurückzugeben:
jq '.autos | length' autos.json
Mit den Funktionen „min“ und „max“ hingegen finden Sie schnell das minimale oder maximale Element eines Eingabe-Arrays. Mit der Funktion „test“ können Sie dagegen prüfen, ob eine Eingabe mit einem bestimmten regulären Ausdruck übereinstimmt: Folgendes Beispiel gibt den Preis sämtlicher Autos aus, deren Name mit dem Buchstaben „a“ beginnt.
Ein weiterer häufiger Anwendungsfall besteht darin, eindeutige Vorkommen eines bestimmten Werts in einem Array zu ermitteln oder Duplikate zu entfernen. Das vorangestellte Beispiel prüft, wie viele einzigartige Farben das autos-Dokument enthält.
Schließlich unterstützt jq auch das Slicing von Arrays. Dies ist besonders nützlich, wenn Sie ein Sub-Array eines Arrays zurückgeben müssen.
echo '[1,2,3,4,5,6,7,8,9,10]' | jq '.[6:9]'
In diesem Beispiel ist das Ergebnis ein neues Array mit einer Länge von 3, das die Elemente von Index 5 (einschließlich) bis Index 8 (exklusiv) enthält. Es ist ebenfalls möglich, einen der Indizes wegzulassen:
echo '[1,2,3,4,5,6,7,8,9,10]' | jq '.[:5]' | jq '.[-2:]'
(ID:47489255)