jq: Druckschlüssel und Wert für jeden Eintrag in einem Objekt

77

Wie bringe ich jq dazu, json so zu nehmen:

{
  "host1": { "ip": "10.1.2.3" },
  "host2": { "ip": "10.1.2.2" },
  "host3": { "ip": "10.1.18.1" }
}

und generieren Sie diese Ausgabe:

host1, 10.1.2.3
host2, 10.1.2.2
host3, 10.1.18.1

Ich bin nicht an der Formatierung interessiert, ich kann nur nicht herausfinden, wie ich auf den Schlüsselnamen und den Wert zugreifen soll.

Jeff Tang
quelle

Antworten:

120

Um die Schlüssel der obersten Ebene als Stream abzurufen, können Sie die integrierte Funktion verwenden keys[] . Eine Lösung für Ihr spezielles Problem wäre also:

jq -r 'keys[] as $k | "\($k), \(.[$k] | .ip)"' 

keyserzeugt die Schlüsselnamen in sortierter Reihenfolge; Wenn Sie sie in der ursprünglichen Reihenfolge möchten, verwenden Sie keys_unsorted.

Eine andere Alternative, die Schlüssel in der ursprünglichen Reihenfolge erzeugt, ist:

jq -r 'to_entries[] | "\(.key), \(.value | .ip)"'

CSV- und TSV-Ausgabe

Die Filter @csv und @tsv könnten hier ebenfalls eine Überlegung wert sein, z

jq -r 'to_entries[] | [.key, .value.ip] | @tsv'

produziert:

host1   10.1.2.3
host2   10.1.2.2
host3   10.1.18.1

Eingebettete Objekte

Wenn die interessierenden Schlüssel wie im folgenden Beispiel eingebettet sind, müsste der jq-Filter gemäß den gezeigten Linien geändert werden.

Eingang:

{
  "myhosts": {
    "host1": { "ip": "10.1.2.3" },
    "host2": { "ip": "10.1.2.2" },
    "host3": { "ip": "10.1.18.1" }
  }
}

Änderung:

jq -r '.myhosts | keys[] as $k | "\($k), \(.[$k] | .ip)"'
Gipfel
quelle
Angenommen, der Schlüssel ".ip" enthält Leerzeichen, z. B. "IP-Adresse". Wie würden Sie die Anführungszeichen um den Schlüssel umgehen, wenn Sie sich auf der dritten Ebene einer Zeichenfolge in Anführungszeichen befinden, wenn dies sinnvoll ist?
Saichovsky
1
Ja, es macht Sinn und es ist eine gute Frage, aber verzeihen Sie mir, dass Sie sie leicht selbst hätten beantworten können, da die Antwort einfach darin besteht, die möglichen Komplikationen zu ignorieren. Das heißt, der normale Ansatz wäre gewesen, die Zeichenfolge mit Leerzeichen et voilà zu zitieren.
Höhepunkt
Ich hatte das ohne Erfolg versucht. Ich habe versucht, den Zitaten zu entkommen, aber es hat nicht funktioniert, daher die Frage.
Saichovsky
1
@ Saichovsky - Ich habe überprüft, ob es in jq 1.4, 1.5 und 1.6 funktioniert. Wenn Sie jq 1.3 verwenden, müssten Sie schreiben .["id address"], wie Sie es ohnehin im Normalfall tun müssten.
Höhepunkt
45

Kam über sehr elegante Lösung

jq 'with_entries(.value |= .ip)'

Welche Ausgaben

{
  "host1": "10.1.2.3",
  "host2": "10.1.2.2",
  "host3": "10.1.18.1"
}

Hier ist das jqplay-Snippet zum Spielen: https://jqplay.org/s/Jb_fnBveMQ

Die Funktion with_entrieswandelt jedes Objekt in der Liste der Objekte zu Schlüssel / Wert-Paar, so können wir zugreifen .keyoder .valuejeweils Wir aktualisieren (überschreiben) jedes KV-Element .valuemit dem Feld .ipvon Update mit |=Operator

Viacheslav
quelle
Diese Lösung ist die genaue Antwort. Die ausgewählte Lösung verfügt über Extras, die hilfreich, aber nicht so genau oder elegant sind. Möglicherweise möchten Sie eine kurze Erklärung und den vollständigen Befehl hinzufügen.
Mike D
Hervorragend! Oft habe ich "to_entries []" verwendet, nur weil ich diesen nicht kannte.
Lungang Fang