jq — JSON auf der Kommandozeile verarbeiten
Praxis-Guide zu jq: JSON auf der Kommandozeile filtern, transformieren und abfragen — die jq-Abfragesprache von Pretty-Print bis select().
jq ist ein leichtgewichtiger, flexibler JSON-Prozessor für die Kommandozeile – du pipest JSON aus curl, cat oder einem anderen Befehl hinein und arbeitest damit genauso wie du es von sed, awk oder grep für Text gewohnt bist. Statt JSON mühsam mit Zeilen-Tools zu zerlegen, nutzt du jqs eigene Abfragesprache: Filter, die du mit Pipes | verkettest, Feldzugriffe per Punkt-Notation und select() zum gezielten Filtern. Mit -r gibst du rohe Strings ohne JSON-Anführungszeichen aus – ideal, wenn du Werte in Shell-Skripten weiterverarbeiten willst. Dieser Guide zeigt dir die Filter und Muster, die du im Alltag wirklich brauchst – vom Pretty-Print bis zur Aggregation ganzer Datensätze.
Grundlagen
jq '.' <file> — Gibt eine JSON-Datei mit Syntax-Highlighting formatiert aus (Pretty-Print).
jq '.' data.jsoncat <file> | jq '.' — Gibt JSON aus der Standardeingabe formatiert aus (Pipe von einem anderen Befehl).
curl -s https://api.example.com/users | jq '.'jq -c '.' <file> — Kompakte Ausgabe — gibt JSON in einer einzigen Zeile aus.
jq -c '.' data.jsonjq -r '.' <file> — Rohe Ausgabe — gibt Strings ohne JSON-Anführungszeichen aus (praktisch für Shell-Skripte).
jq -r '.name' user.jsonjq -n '<expr>' — Null-Input-Modus — wertet einen Ausdruck aus, ohne eine Eingabe zu lesen.
jq -n '{name: "Alice", age: 30}'jq -s '.' <files> — Slurp-Modus — liest alle Eingaben in ein Array ein, statt jede Zeile einzeln zu verarbeiten.
jq -s '.' a.json b.jsonjq -e '<filter>' <file> — Beendet mit Status 1, wenn die Ausgabe false oder null ist. Praktisch in Shell-Skripten.
jq -e '.active' user.json && echo 'User is active'Feldzugriff & Pfade
jq '.<field>' <file> — Greift auf ein Feld der obersten Ebene über seinen Namen zu.
jq '.name' user.jsonjq '.<field>.<nested>' <file> — Greift über Punkt-Notation auf ein verschachteltes Feld zu.
jq '.address.city' user.jsonjq '.["<field>"]' <file> — Greift über Klammer-Notation auf ein Feld zu. Nötig für Felder mit Sonderzeichen oder Bindestrichen.
jq '["content-type"]' headers.jsonjq '.<field>?' <file> — Optionaler Feldzugriff — unterdrückt Fehler, falls das Feld nicht existiert.
jq '.nickname?' user.jsonjq '.a, .b, .c' <file> — Wählt mehrere Felder aus. Gibt jeden Wert in einer eigenen Zeile aus.
jq '.name, .email, .age' user.jsonjq 'path(..<field>)' <file> — Gibt den Pfad (als Array) zu einem Feld irgendwo in der Struktur zurück.
jq 'path(..id?)' data.jsonArray-Operationen
jq '.[]' <file> — Iteriert über alle Elemente eines Arrays oder die Werte eines Objekts.
jq '.[]' users.jsonjq '.[<n>]' <file> — Greift auf das Element an Index n zu (nullbasiert). Negative Indizes zählen vom Ende.
jq '.[0]' users.jsonjq '.[-1]' <file> — Greift auf das letzte Element eines Arrays zu.
jq '.[-1]' items.jsonjq '.[<from>:<to>]' <file> — Schneidet ein Array von Index 'from' (inklusive) bis 'to' (exklusive) aus.
jq '.[2:5]' items.jsonjq 'length' <file> — Gibt die Anzahl der Elemente eines Arrays, der Zeichen eines Strings oder der Schlüssel eines Objekts zurück.
jq '.users | length' data.jsonjq 'first' <file> — Gibt das erste von einem Ausdruck erzeugte Element zurück.
jq 'first(.users[])' data.jsonjq 'last' <file> — Gibt das letzte von einem Ausdruck erzeugte Element zurück.
jq 'last(.users[])' data.jsonjq 'reverse' <file> — Kehrt ein Array um.
jq '.items | reverse' data.jsonjq 'flatten' <file> — Verflacht ein verschachteltes Array zu einem einstufigen Array.
jq '.tags | flatten' data.jsonjq 'flatten(<depth>)' <file> — Verflacht ein verschachteltes Array bis zur angegebenen Tiefe.
jq '.nested | flatten(1)' data.jsonjq 'unique' <file> — Entfernt doppelte Werte aus einem Array.
jq '.tags | unique' data.jsonjq 'add' <file> — Summiert ein Array von Zahlen, verkettet Strings oder verschmilzt ein Array von Objekten.
jq '.prices | add' cart.jsonObjekte konstruieren
jq '{<key>: .<field>}' <file> — Konstruiert ein neues Objekt mit einem bestimmten Schlüssel und Wert.
jq '{id: .id, username: .name}' user.jsonjq '{<field>}' <file> — Kurzform: nutzt den Feldnamen sowohl als Schlüssel als auch als Wertpfad.
jq '{name, email}' user.jsonjq '{(<expr>): <value>}' <file> — Nutzt einen berechneten Ausdruck als Objektschlüssel.
jq '{(.name): .score}' result.jsonjq '. + {<key>: <value>}' <file> — Fügt ein Feld hinzu oder überschreibt es mit dem Merge-Operator.
jq '. + {active: true}' user.jsonjq 'del(.<field>)' <file> — Entfernt ein Feld aus einem Objekt.
jq 'del(.password)' user.jsonjq 'del(.<field>, .<field2>)' <file> — Entfernt mehrere Felder aus einem Objekt.
jq 'del(.password, .token)' user.jsonFiltern & Auswählen
jq '.[] | select(.<field> == <value>)' <file> — Filtert Array-Elemente, bei denen ein Feld einem bestimmten Wert entspricht.
jq '.[] | select(.active == true)' users.jsonjq '.[] | select(.<field> > <n>)' <file> — Filtert Elemente, bei denen ein numerisches Feld einen Schwellenwert überschreitet.
jq '.[] | select(.age > 18)' users.jsonjq '.[] | select(.<field> | test("<regex>"))' <file> — Filtert Elemente, bei denen ein String-Feld auf einen regulären Ausdruck passt.
jq '.[] | select(.email | test("@gmail\.com$"))' users.jsonjq '.[] | select(.<field> != null)' <file> — Filtert Elemente, bei denen ein Feld nicht null ist (Feld existiert und hat einen Wert).
jq '.[] | select(.phone != null)' users.jsonjq '.[] | select(has("<field>"))' <file> — Filtert Elemente, die einen bestimmten Schlüssel enthalten.
jq '.[] | select(has("avatar"))' users.jsonjq 'if <cond> then <a> else <b> end' <file> — Bedingter Ausdruck — gibt je nach Bedingung den einen oder den anderen Wert zurück.
jq 'if .active then "enabled" else "disabled" end' user.jsonjq '.<field> // <default>' <file> — Alternativ-Operator — nutzt einen Standardwert, wenn das Ergebnis null oder false ist.
jq '.nickname // .name' user.jsonTransformieren & Mappen
jq 'map(<expr>)' <file> — Wendet einen Ausdruck auf jedes Element eines Arrays an. Entspricht [.[] |
jq '.users | map(.name)' data.jsonjq 'map(select(<cond>))' <file> — Filtert ein Array auf Elemente, die einer Bedingung entsprechen (map + select).
jq '.users | map(select(.active == true))' data.jsonjq 'map_values(<expr>)' <file> — Wendet einen Ausdruck auf jeden Wert eines Objekts oder Arrays an.
jq 'map_values(. * 2)' scores.jsonjq '[.[] | <expr>]' <file> — Sammelt die Ergebnisse eines Ausdrucks per Array-Konstruktion in ein neues Array.
jq '[.items[] | .price]' cart.jsonjq '.[] | {<key>: .<field>}' <file> — Formt jedes Element eines Arrays in eine neue Objektgestalt um.
jq '.users[] | {id: .id, label: .name}' data.jsonjq '[.[] | {<key>: .<field>}]' <file> — Formt ein Array in ein neues Array umgestalteter Objekte um.
jq '[.users[] | {id: .id, label: .name}]' data.jsonSchlüssel, Werte & Einträge
jq 'keys' <file> — Gibt ein sortiertes Array der Schlüssel eines Objekts zurück.
jq 'keys' config.jsonjq 'keys_unsorted' <file> — Gibt die Schlüssel eines Objekts in ihrer ursprünglichen Einfügereihenfolge zurück.
jq 'keys_unsorted' config.jsonjq 'values' <file> — Gibt ein Array der Werte eines Objekts zurück.
jq '.settings | values' config.jsonjq 'has("<key>")' <file> — Gibt true zurück, wenn das Objekt den angegebenen Schlüssel oder das Array den angegebenen Index enthält.
jq 'has("email")' user.jsonjq 'in' <file> — Gibt true zurück, wenn der linke Wert ein Schlüssel im rechten Objekt ist.
jq '.[] | in({"a":1, "b":2})' keys.jsonjq 'to_entries' <file> — Wandelt ein Objekt in ein Array von {key, value}-Paaren um.
jq '. | to_entries' config.jsonjq 'from_entries' <file> — Wandelt ein Array von {key, value}-Paaren zurück in ein Objekt um.
jq '. | from_entries' pairs.jsonjq 'with_entries(<expr>)' <file> — Wendet einen Ausdruck auf jedes {key, value}-Paar eines Objekts an. Kurzform für to_entries | map(
jq 'with_entries(select(.value != null))' config.jsonSortieren, Gruppieren & Aggregieren
jq 'sort' <file> — Sortiert ein Array vergleichbarer Werte.
jq '.scores | sort' data.jsonjq 'sort_by(.<field>)' <file> — Sortiert ein Array von Objekten nach einem bestimmten Feld.
jq '.users | sort_by(.name)' data.jsonjq 'sort_by(.<field>) | reverse' <file> — Sortiert ein Array absteigend nach einem Feld.
jq '.users | sort_by(.age) | reverse' data.jsonjq 'group_by(.<field>)' <file> — Gruppiert ein Array von Objekten nach dem Wert eines bestimmten Feldes.
jq '.orders | group_by(.status)' data.jsonjq 'unique_by(.<field>)' <file> — Entfernt Duplikate aus einem Array anhand eines bestimmten Feldes.
jq '.users | unique_by(.email)' data.jsonjq 'min_by(.<field>)' <file> — Gibt das Element mit dem kleinsten Wert für ein bestimmtes Feld zurück.
jq '.products | min_by(.price)' data.jsonjq 'max_by(.<field>)' <file> — Gibt das Element mit dem größten Wert für ein bestimmtes Feld zurück.
jq '.products | max_by(.price)' data.jsonjq '[.[] | .<field>] | add' <file> — Summiert ein numerisches Feld über alle Elemente eines Arrays.
jq '[.items[] | .price] | add' cart.jsonjq 'reduce .[] as $x (0; . + $x)' <file> — Reduziert ein Array per Akkumulator auf einen einzigen Wert. Hier: alle Zahlen summieren.
jq 'reduce .[] as $x (0; . + $x)' numbers.jsonString-Operationen
jq 'test("<regex>")' <file> — Gibt true zurück, wenn ein String auf einen regulären Ausdruck passt.
jq '.email | test("@gmail\.com$")' user.jsonjq 'ascii_downcase' <file> — Wandelt einen String in Kleinbuchstaben um.
jq '.name | ascii_downcase' user.jsonjq 'ascii_upcase' <file> — Wandelt einen String in Großbuchstaben um.
jq '.status | ascii_upcase' item.jsonjq 'ltrimstr("<prefix>")' <file> — Entfernt einen Präfix vom String, falls vorhanden.
jq '.url | ltrimstr("https://")' link.jsonjq 'rtrimstr("<suffix>")' <file> — Entfernt einen Suffix vom String, falls vorhanden.
jq '.filename | rtrimstr(".json")' file.jsonjq 'startswith("<str>")' <file> — Gibt true zurück, wenn der String mit dem angegebenen Präfix beginnt.
jq '.url | startswith("https")' link.jsonjq 'endswith("<str>")' <file> — Gibt true zurück, wenn der String mit dem angegebenen Suffix endet.
jq '.filename | endswith(".json")' file.jsonjq 'split("<delim>")' <file> — Teilt einen String an einem Trennzeichen in ein Array auf.
jq '.tags | split(",")' item.jsonjq 'join("<delim>")' <file> — Verbindet ein Array von Strings mit einem Trennzeichen zu einem einzigen String.
jq '.tags | join(", ")' item.jsonjq '"prefix \(.field) suffix"' <file> — String-Interpolation — bettet Ausdrücke per (...) in einen String ein.
jq '"Hello, \(.name)! You are \(.age) years old."' user.jsonjq '@base64' <file> — Kodiert einen String als Base64.
jq '.data | @base64' file.jsonjq '@base64d' <file> — Dekodiert einen Base64-kodierten String.
jq '.encoded | @base64d' file.jsonjq '@uri' <file> — Prozent-kodiert einen String zur Verwendung in URLs.
jq '.query | @uri' search.jsonjq '@csv' <file> — Formatiert ein Array als CSV-Zeile (String).
jq '.rows[] | @csv' data.jsonjq '@tsv' <file> — Formatiert ein Array als tabulatorgetrennte Zeile (TSV-String).
jq '.rows[] | @tsv' data.jsonjq '@html' <file> — Maskiert HTML-Sonderzeichen (<, >, &, ', ") in einem String.
jq '.body | @html' post.jsonjq '@sh' <file> — Formatiert einen String oder ein Array als shell-escapte Argumente.
jq '@sh "echo \(.name)"' user.jsonTypen & Konvertierung
jq 'type' <file> — Gibt den JSON-Typ eines Werts zurück: null, boolean, number, string, array oder object.
jq '.value | type' data.jsonjq 'tostring' <file> — Wandelt einen beliebigen Wert in seine JSON-String-Darstellung um.
jq '.count | tostring' data.jsonjq 'tonumber' <file> — Wandelt einen String in eine Zahl um.
jq '.price | tonumber' item.jsonjq 'not' <file> — Negiert einen booleschen Wert.
jq '.active | not' user.jsonjq 'infinite' <file> — Erzeugt den IEEE-754-Wert für unendlich.
jq -n 'infinite'jq 'nan' <file> — Erzeugt einen IEEE-754-NaN-Wert.
jq -n 'nan'jq 'isinfinite' <file> — Gibt true zurück, wenn eine Zahl unendlich ist.
jq '.value | isinfinite' data.jsonjq 'isnan' <file> — Gibt true zurück, wenn ein Wert NaN ist.
jq '.value | isnan' data.jsonjq 'isnormal' <file> — Gibt true zurück, wenn eine Zahl eine normale, endliche Zahl ist.
jq '.value | isnormal' data.jsonRekursion & Pfad-Operationen
jq '.. | .<field>?' <file> — Durchsucht rekursiv alle Nachfahren nach einem bestimmten Feld (rekursiver Abstieg).
jq '.. | .id?' data.jsonjq '[paths]' <file> — Gibt alle Pfade in der JSON-Struktur als Arrays zurück.
jq '[paths]' config.jsonjq '[leaf_paths]' <file> — Gibt die Pfade zu allen Blatt-Werten (Nicht-Container) zurück.
jq '[leaf_paths]' config.jsonjq 'getpath(["<a>","<b>"])' <file> — Holt einen Wert an einem als Array angegebenen Pfad.
jq 'getpath(["address","city"])' user.jsonjq 'setpath(["<a>","<b>"]; <value>)' <file> — Setzt einen Wert an einem als Array angegebenen Pfad.
jq 'setpath(["address","city"]; "Berlin")' user.jsonjq 'delpaths([["<a>"],["<b>"]])' <file> — Löscht Werte an mehreren angegebenen Pfaden.
jq 'delpaths([["password"],["token"]])' user.jsonVariablen & Definitionen
jq '.<field> as $<var> | <expr>' <file> — Weist einen Wert einer benannten Variablen zu, um ihn in einem späteren Ausdruck wiederzuverwenden.
jq '.total as $t | .items[] | {name, pct: (.price / $t * 100)}' data.jsonjq --arg <var> '<value>' '<expr>' <file> — Übergibt eine Shell-Variable als String-Variable an jq.
jq --arg name "Alice" '.[] | select(.name == $name)' users.jsonjq --argjson <var> '<json>' '<expr>' <file> — Übergibt eine Shell-Variable als geparsten JSON-Wert an jq.
jq --argjson minAge 18 '.[] | select(.age >= $minAge)' users.jsonjq 'def <name>: <body>; <expr>' <file> — Definiert eine wiederverwendbare Funktion inline.
jq 'def double: . * 2; .values[] | double' data.jsonjq -f <file.jq> <file> — Liest einen jq-Filter aus einer Datei statt aus einem Kommandozeilen-Argument.
jq -f transform.jq data.jsonjq 'env.<VAR>' — Greift über den Namen auf eine Umgebungsvariable zu.
jq -n 'env.HOME'jq '$ENV.<VAR>' — Greift über das $ENV-Objekt auf Umgebungsvariablen zu.
jq -n '$ENV.PATH'Fehlerbehandlung
jq 'try <expr>' <file> — Versucht einen Ausdruck und unterdrückt alle dabei auftretenden Fehler.
jq '.[] | try .value' mixed.jsonjq 'try <expr> catch <handler>' <file> — Versucht einen Ausdruck und führt einen Handler aus, wenn er fehlschlägt. Die Fehlermeldung steht dem Handler als Eingabe zur Verfügung.
jq 'try tonumber catch "not a number"' values.jsonjq 'error("<message>")' <file> — Löst einen eigenen Fehler aus und stoppt die Verarbeitung.
jq 'if .status != "ok" then error("unexpected status") else . end' resp.jsonjq '.[]?' <file> — Iteriert mit dem optionalen Operator — unterdrückt Fehler, falls der Wert nicht iterierbar ist.
jq '.items[]?' data.jsonPraxisbeispiele
curl -s <api_url> | jq '.' — Gibt eine JSON-API-Antwort formatiert aus.
curl -s https://api.github.com/users/octocat | jq '.'jq '.[] | select(.status == "active") | .name' <file> — Extrahiert die Namen aller aktiven Nutzer als reine Strings (-r für rohe Ausgabe).
jq -r '.[] | select(.status == "active") | .name' users.jsonjq 'del(.[] | .password, .token)' <file> — Entfernt sensible Felder aus jedem Objekt eines Arrays.
jq 'del(.[] | .password, .token)' users.jsonjq '[.[] | {key: .id, value: .name}] | from_entries' <file> — Wandelt ein Array von Objekten in eine nach id geschlüsselte Nachschlagekarte um.
jq '[.[] | {key: (.id|tostring), value: .name}] | from_entries' users.jsonjq 'group_by(.category) | map({category: .[0].category, count: length})' <file> — Zählt Einträge pro Kategorie.
jq 'group_by(.category) | map({category: .[0].category, count: length})' items.jsonjq -r '[.name, .email, .age | tostring] | @csv' <file> — Exportiert ausgewählte Felder als CSV-Zeile.
jq -r '.[] | [.name, .email, (.age|tostring)] | @csv' users.jsonjq -s '.[0] * .[1]' <file1> <file2> — Tief-verschmilzt zwei JSON-Objekte (der Operator * verschmilzt Objekte rekursiv).
jq -s '.[0] * .[1]' defaults.json overrides.jsonjq 'to_entries | map(select(.value == null)) | map(.key)' <file> — Findet alle Schlüssel mit null-Werten in einem Objekt.
jq 'to_entries | map(select(.value == null)) | map(.key)' config.jsonjq -r 'path(..)|map(tostring)|join(".")' <file> — Gibt alle Schlüsselpfade in Punkt-Notation aus (praktisch zum Erkunden tiefer Strukturen).
jq -r '[path(..)|map(tostring)|join(".")]|unique[]' config.jsonjq -R 'split(" ") | {method: .[0], path: .[1], status: .[2]}' <file> — Parst Klartext-Zeilen in JSON-Objekte (-R liest rohe Strings als Eingabe).
jq -R 'split(" ") | {method: .[0], path: .[1]}' access.log Fazit
jq ist read-only und damit von Natur aus sicher – es liest JSON, verändert aber niemals deine Quelldatei, sondern schreibt das Ergebnis auf die Standardausgabe. Im Alltag kommst du mit einer Handvoll Bausteine weit: .feld für Zugriffe, | zum Verketten, select() zum Filtern und map() zum Transformieren. Vorsicht ist bei der rohen Ausgabe mit -r geboten: Sobald du die Werte in der Shell weiterverarbeitest, musst du selbst auf korrektes Quoting achten, denn Leerzeichen, Zeilenumbrüche oder Sonderzeichen in den Daten können dein Skript sonst unterlaufen. Und behandle JSON aus unvertrauenswürdigen Quellen mit derselben Skepsis wie jeden anderen Fremd-Input – validiere die Struktur, bevor du dich auf bestimmte Felder verlässt.
Weiterführende Links
- jq-Handbuch – die offizielle, vollständige Referenz zur jq-Abfragesprache (englisch)
- jq auf Wikipedia – deutschsprachiger Überblick zu Geschichte und Einsatz von jq
- jq play – interaktive Spielwiese, um jq-Filter direkt im Browser auszuprobieren (englisch)