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.json

cat <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.json

jq -r '.' <file> — Rohe Ausgabe — gibt Strings ohne JSON-Anführungszeichen aus (praktisch für Shell-Skripte).

jq -r '.name' user.json

jq -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.json

jq -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.json

jq '.<field>.<nested>' <file> — Greift über Punkt-Notation auf ein verschachteltes Feld zu.

jq '.address.city' user.json

jq '.["<field>"]' <file> — Greift über Klammer-Notation auf ein Feld zu. Nötig für Felder mit Sonderzeichen oder Bindestrichen.

jq '["content-type"]' headers.json

jq '.<field>?' <file> — Optionaler Feldzugriff — unterdrückt Fehler, falls das Feld nicht existiert.

jq '.nickname?' user.json

jq '.a, .b, .c' <file> — Wählt mehrere Felder aus. Gibt jeden Wert in einer eigenen Zeile aus.

jq '.name, .email, .age' user.json

jq 'path(..<field>)' <file> — Gibt den Pfad (als Array) zu einem Feld irgendwo in der Struktur zurück.

jq 'path(..id?)' data.json

Array-Operationen

jq '.[]' <file> — Iteriert über alle Elemente eines Arrays oder die Werte eines Objekts.

jq '.[]' users.json

jq '.[<n>]' <file> — Greift auf das Element an Index n zu (nullbasiert). Negative Indizes zählen vom Ende.

jq '.[0]' users.json

jq '.[-1]' <file> — Greift auf das letzte Element eines Arrays zu.

jq '.[-1]' items.json

jq '.[<from>:<to>]' <file> — Schneidet ein Array von Index 'from' (inklusive) bis 'to' (exklusive) aus.

jq '.[2:5]' items.json

jq '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.json

jq 'first' <file> — Gibt das erste von einem Ausdruck erzeugte Element zurück.

jq 'first(.users[])' data.json

jq 'last' <file> — Gibt das letzte von einem Ausdruck erzeugte Element zurück.

jq 'last(.users[])' data.json

jq 'reverse' <file> — Kehrt ein Array um.

jq '.items | reverse' data.json

jq 'flatten' <file> — Verflacht ein verschachteltes Array zu einem einstufigen Array.

jq '.tags | flatten' data.json

jq 'flatten(<depth>)' <file> — Verflacht ein verschachteltes Array bis zur angegebenen Tiefe.

jq '.nested | flatten(1)' data.json

jq 'unique' <file> — Entfernt doppelte Werte aus einem Array.

jq '.tags | unique' data.json

jq 'add' <file> — Summiert ein Array von Zahlen, verkettet Strings oder verschmilzt ein Array von Objekten.

jq '.prices | add' cart.json

Objekte konstruieren

jq '{<key>: .<field>}' <file> — Konstruiert ein neues Objekt mit einem bestimmten Schlüssel und Wert.

jq '{id: .id, username: .name}' user.json

jq '{<field>}' <file> — Kurzform: nutzt den Feldnamen sowohl als Schlüssel als auch als Wertpfad.

jq '{name, email}' user.json

jq '{(<expr>): <value>}' <file> — Nutzt einen berechneten Ausdruck als Objektschlüssel.

jq '{(.name): .score}' result.json

jq '. + {<key>: <value>}' <file> — Fügt ein Feld hinzu oder überschreibt es mit dem Merge-Operator.

jq '. + {active: true}' user.json

jq 'del(.<field>)' <file> — Entfernt ein Feld aus einem Objekt.

jq 'del(.password)' user.json

jq 'del(.<field>, .<field2>)' <file> — Entfernt mehrere Felder aus einem Objekt.

jq 'del(.password, .token)' user.json

Filtern & Auswählen

jq '.[] | select(.<field> == <value>)' <file> — Filtert Array-Elemente, bei denen ein Feld einem bestimmten Wert entspricht.

jq '.[] | select(.active == true)' users.json

jq '.[] | select(.<field> > <n>)' <file> — Filtert Elemente, bei denen ein numerisches Feld einen Schwellenwert überschreitet.

jq '.[] | select(.age > 18)' users.json

jq '.[] | 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.json

jq '.[] | select(.<field> != null)' <file> — Filtert Elemente, bei denen ein Feld nicht null ist (Feld existiert und hat einen Wert).

jq '.[] | select(.phone != null)' users.json

jq '.[] | select(has("<field>"))' <file> — Filtert Elemente, die einen bestimmten Schlüssel enthalten.

jq '.[] | select(has("avatar"))' users.json

jq '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.json

jq '.<field> // <default>' <file> — Alternativ-Operator — nutzt einen Standardwert, wenn das Ergebnis null oder false ist.

jq '.nickname // .name' user.json

Transformieren & Mappen

jq 'map(<expr>)' <file> — Wendet einen Ausdruck auf jedes Element eines Arrays an. Entspricht [.[] | ].

jq '.users | map(.name)' data.json

jq 'map(select(<cond>))' <file> — Filtert ein Array auf Elemente, die einer Bedingung entsprechen (map + select).

jq '.users | map(select(.active == true))' data.json

jq 'map_values(<expr>)' <file> — Wendet einen Ausdruck auf jeden Wert eines Objekts oder Arrays an.

jq 'map_values(. * 2)' scores.json

jq '[.[] | <expr>]' <file> — Sammelt die Ergebnisse eines Ausdrucks per Array-Konstruktion in ein neues Array.

jq '[.items[] | .price]' cart.json

jq '.[] | {<key>: .<field>}' <file> — Formt jedes Element eines Arrays in eine neue Objektgestalt um.

jq '.users[] | {id: .id, label: .name}' data.json

jq '[.[] | {<key>: .<field>}]' <file> — Formt ein Array in ein neues Array umgestalteter Objekte um.

jq '[.users[] | {id: .id, label: .name}]' data.json

Schlüssel, Werte & Einträge

jq 'keys' <file> — Gibt ein sortiertes Array der Schlüssel eines Objekts zurück.

jq 'keys' config.json

jq 'keys_unsorted' <file> — Gibt die Schlüssel eines Objekts in ihrer ursprünglichen Einfügereihenfolge zurück.

jq 'keys_unsorted' config.json

jq 'values' <file> — Gibt ein Array der Werte eines Objekts zurück.

jq '.settings | values' config.json

jq '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.json

jq 'in' <file> — Gibt true zurück, wenn der linke Wert ein Schlüssel im rechten Objekt ist.

jq '.[] | in({"a":1, "b":2})' keys.json

jq 'to_entries' <file> — Wandelt ein Objekt in ein Array von {key, value}-Paaren um.

jq '. | to_entries' config.json

jq 'from_entries' <file> — Wandelt ein Array von {key, value}-Paaren zurück in ein Objekt um.

jq '. | from_entries' pairs.json

jq 'with_entries(<expr>)' <file> — Wendet einen Ausdruck auf jedes {key, value}-Paar eines Objekts an. Kurzform für to_entries | map() | from_entries.

jq 'with_entries(select(.value != null))' config.json

Sortieren, Gruppieren & Aggregieren

jq 'sort' <file> — Sortiert ein Array vergleichbarer Werte.

jq '.scores | sort' data.json

jq 'sort_by(.<field>)' <file> — Sortiert ein Array von Objekten nach einem bestimmten Feld.

jq '.users | sort_by(.name)' data.json

jq 'sort_by(.<field>) | reverse' <file> — Sortiert ein Array absteigend nach einem Feld.

jq '.users | sort_by(.age) | reverse' data.json

jq 'group_by(.<field>)' <file> — Gruppiert ein Array von Objekten nach dem Wert eines bestimmten Feldes.

jq '.orders | group_by(.status)' data.json

jq 'unique_by(.<field>)' <file> — Entfernt Duplikate aus einem Array anhand eines bestimmten Feldes.

jq '.users | unique_by(.email)' data.json

jq 'min_by(.<field>)' <file> — Gibt das Element mit dem kleinsten Wert für ein bestimmtes Feld zurück.

jq '.products | min_by(.price)' data.json

jq '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.json

jq '[.[] | .<field>] | add' <file> — Summiert ein numerisches Feld über alle Elemente eines Arrays.

jq '[.items[] | .price] | add' cart.json

jq '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.json

String-Operationen

jq 'test("<regex>")' <file> — Gibt true zurück, wenn ein String auf einen regulären Ausdruck passt.

jq '.email | test("@gmail\.com$")' user.json

jq 'ascii_downcase' <file> — Wandelt einen String in Kleinbuchstaben um.

jq '.name | ascii_downcase' user.json

jq 'ascii_upcase' <file> — Wandelt einen String in Großbuchstaben um.

jq '.status | ascii_upcase' item.json

jq 'ltrimstr("<prefix>")' <file> — Entfernt einen Präfix vom String, falls vorhanden.

jq '.url | ltrimstr("https://")' link.json

jq 'rtrimstr("<suffix>")' <file> — Entfernt einen Suffix vom String, falls vorhanden.

jq '.filename | rtrimstr(".json")' file.json

jq 'startswith("<str>")' <file> — Gibt true zurück, wenn der String mit dem angegebenen Präfix beginnt.

jq '.url | startswith("https")' link.json

jq 'endswith("<str>")' <file> — Gibt true zurück, wenn der String mit dem angegebenen Suffix endet.

jq '.filename | endswith(".json")' file.json

jq 'split("<delim>")' <file> — Teilt einen String an einem Trennzeichen in ein Array auf.

jq '.tags | split(",")' item.json

jq 'join("<delim>")' <file> — Verbindet ein Array von Strings mit einem Trennzeichen zu einem einzigen String.

jq '.tags | join(", ")' item.json

jq '"prefix \(.field) suffix"' <file> — String-Interpolation — bettet Ausdrücke per (...) in einen String ein.

jq '"Hello, \(.name)! You are \(.age) years old."' user.json

jq '@base64' <file> — Kodiert einen String als Base64.

jq '.data | @base64' file.json

jq '@base64d' <file> — Dekodiert einen Base64-kodierten String.

jq '.encoded | @base64d' file.json

jq '@uri' <file> — Prozent-kodiert einen String zur Verwendung in URLs.

jq '.query | @uri' search.json

jq '@csv' <file> — Formatiert ein Array als CSV-Zeile (String).

jq '.rows[] | @csv' data.json

jq '@tsv' <file> — Formatiert ein Array als tabulatorgetrennte Zeile (TSV-String).

jq '.rows[] | @tsv' data.json

jq '@html' <file> — Maskiert HTML-Sonderzeichen (<, >, &, ', ") in einem String.

jq '.body | @html' post.json

jq '@sh' <file> — Formatiert einen String oder ein Array als shell-escapte Argumente.

jq '@sh "echo \(.name)"' user.json

Typen & Konvertierung

jq 'type' <file> — Gibt den JSON-Typ eines Werts zurück: null, boolean, number, string, array oder object.

jq '.value | type' data.json

jq 'tostring' <file> — Wandelt einen beliebigen Wert in seine JSON-String-Darstellung um.

jq '.count | tostring' data.json

jq 'tonumber' <file> — Wandelt einen String in eine Zahl um.

jq '.price | tonumber' item.json

jq 'not' <file> — Negiert einen booleschen Wert.

jq '.active | not' user.json

jq '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.json

jq 'isnan' <file> — Gibt true zurück, wenn ein Wert NaN ist.

jq '.value | isnan' data.json

jq 'isnormal' <file> — Gibt true zurück, wenn eine Zahl eine normale, endliche Zahl ist.

jq '.value | isnormal' data.json

Rekursion & Pfad-Operationen

jq '.. | .<field>?' <file> — Durchsucht rekursiv alle Nachfahren nach einem bestimmten Feld (rekursiver Abstieg).

jq '.. | .id?' data.json

jq '[paths]' <file> — Gibt alle Pfade in der JSON-Struktur als Arrays zurück.

jq '[paths]' config.json

jq '[leaf_paths]' <file> — Gibt die Pfade zu allen Blatt-Werten (Nicht-Container) zurück.

jq '[leaf_paths]' config.json

jq 'getpath(["<a>","<b>"])' <file> — Holt einen Wert an einem als Array angegebenen Pfad.

jq 'getpath(["address","city"])' user.json

jq 'setpath(["<a>","<b>"]; <value>)' <file> — Setzt einen Wert an einem als Array angegebenen Pfad.

jq 'setpath(["address","city"]; "Berlin")' user.json

jq 'delpaths([["<a>"],["<b>"]])' <file> — Löscht Werte an mehreren angegebenen Pfaden.

jq 'delpaths([["password"],["token"]])' user.json

Variablen & 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.json

jq --arg <var> '<value>' '<expr>' <file> — Übergibt eine Shell-Variable als String-Variable an jq.

jq --arg name "Alice" '.[] | select(.name == $name)' users.json

jq --argjson <var> '<json>' '<expr>' <file> — Übergibt eine Shell-Variable als geparsten JSON-Wert an jq.

jq --argjson minAge 18 '.[] | select(.age >= $minAge)' users.json

jq 'def <name>: <body>; <expr>' <file> — Definiert eine wiederverwendbare Funktion inline.

jq 'def double: . * 2; .values[] | double' data.json

jq -f <file.jq> <file> — Liest einen jq-Filter aus einer Datei statt aus einem Kommandozeilen-Argument.

jq -f transform.jq data.json

jq '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.json

jq '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.json

jq 'error("<message>")' <file> — Löst einen eigenen Fehler aus und stoppt die Verarbeitung.

jq 'if .status != "ok" then error("unexpected status") else . end' resp.json

jq '.[]?' <file> — Iteriert mit dem optionalen Operator — unterdrückt Fehler, falls der Wert nicht iterierbar ist.

jq '.items[]?' data.json

Praxisbeispiele

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.json

jq 'del(.[] | .password, .token)' <file> — Entfernt sensible Felder aus jedem Objekt eines Arrays.

jq 'del(.[] | .password, .token)' users.json

jq '[.[] | {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.json

jq '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.json

jq -r '[.name, .email, .age | tostring] | @csv' <file> — Exportiert ausgewählte Felder als CSV-Zeile.

jq -r '.[] | [.name, .email, (.age|tostring)] | @csv' users.json

jq -s '.[0] * .[1]' <file1> <file2> — Tief-verschmilzt zwei JSON-Objekte (der Operator * verschmilzt Objekte rekursiv).

jq -s '.[0] * .[1]' defaults.json overrides.json

jq '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.json

jq -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.json

jq -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.

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

Verwandte Kommandos

  • yq – YAML/JSON-Prozessor in jq-Manier
  • grep – Zeilen in Textdateien per Muster durchsuchen
  • sed – Stream-Editor zum Suchen und Ersetzen in Text