Regex mit sed-Befehl zum Parsen von JSON-Text

15

Ich habe diesen json text:

{
    "buildStatus" : {
        "status" : "ERROR",
        "conditions" : [{
                "status" : "OK",
                "metricKey" : "bugs"
            }, {
                "status" : "ERROR",
                "metricKey" : "test_success_density"
            }, {
                "status" : "OK",
                "metricKey" : "vulnerabilities"
            }
        ],
        "periods" : []
    }
}

Ich möchte den Gesamtstatus des buildStatus extrahieren, dh die erwartete Ausgabe war "ERROR"

"buildStatus" : {
    "status" : "ERROR",
    ....
}

Ich habe den folgenden sed-Ausdruck ausprobiert, aber er funktioniert nicht. Er gibt Folgendes zurück OK:

status= sed -E 's/.*\"buildStatus\":.*\"status\":\"([^\"]*)\",.*/\1/' jsonfile

Was mache ich falsch?

user1876040
quelle

Antworten:

16

Analysieren Sie komplexe verschachtelte Datenstrukturen wie JSON oder XML nicht mit regulären Ausdrücken, sondern verwenden Sie einen geeigneten JSON-Parser wie jshon.

Zuerst musst du es installieren:

sudo apt-get install jshon

Dann müssen Sie ihm die JSON-Daten zum Parsen über die Standardeingabe bereitstellen, damit Sie entweder die Ausgabe eines anderen Befehls dort mit einer Pipe |umleiten können ( ) oder eine Datei dorthin umleiten können ( < filename).

Die Argumente, die zum Extrahieren der gewünschten Daten erforderlich sind, sehen folgendermaßen aus:

jshon -e "buildStatus" -e "status" -u
  • -e "buildStatus" wählt das Element mit dem Index "buildStatus" aus dem Wörterbuch der obersten Ebene aus.
  • -e "status" wählt das Element mit dem "Status" -Index aus dem oben ausgewählten Wörterbuch der zweiten Ebene aus.
  • -u konvertiert die ausgewählten Daten von JSON in reine Daten (dh hier werden die Anführungszeichen um die Zeichenfolge entfernt)

Der Befehl, den Sie ausführen, sieht je nachdem, woher Sie die Daten beziehen, folgendermaßen aus:

jshon -e "buildStatus" -e "status" -u < YOUR_INPUT_FILE
YOUR_JSON_PRODUCING_COMMAND | jshon -e "buildStatus" -e "status" -u

Um mehr darüber zu erfahren jshon, können Sie die Manpage lesen, auf die Sie hier online zugreifen können , oder einfach tippen man jshon.

Byte Commander
quelle
6
Es gibt auch jq:jq -r .buildStatus.status
muru
@HTNW Ich habe noch nie diese Antwort gefallen habe, weil „einzelnen XML - Open - Tag“ (das ist , was die Frage zu stellen) ist eine reguläre Sprache (und man kann im Prinzip baut ein vollständiger XML - Parser von regulären Ausdrücken mit Hilfe von Tags, Kommentare entsprechen, cdata Abschnitte und Verwendung eines einfachen Stapels, um den verschachtelten Kontext zu handhaben). Die interessanteste reguläre Sprache in JSON ist jedoch ein String-Literal.
Random832
10

Arbeit für jq:

jq -r '.["buildStatus"]["status"]' file.json

Kann gekürzt werden auf:

jq -r '.buildStatus.status' file.json

-r( --raw-output) gibt den String ohne jsonString-Formatierung aus, dh ohne Anführungszeichen.

Beispiel:

% cat file.json                   
{
    "buildStatus" : {
        "status" : "ERROR",
        "conditions" : [{
                "status" : "OK",
                "metricKey" : "bugs"
            }, {
                "status" : "ERROR",
                "metricKey" : "test_success_density"
            }, {
                "status" : "OK",
                "metricKey" : "vulnerabilities"
            }
        ],
        "periods" : []
    }
}

% jq -r '.["buildStatus"]["status"]' file.json
ERROR

% jq -r '.buildStatus.status' file.json       
ERROR

Wenn noch nicht installiert, installieren Sie es mit (im Universe-Repository verfügbar):

sudo apt-get install jq 
heemayl
quelle
8

Wie bereits erwähnt, ist das Parsen komplex strukturierter Daten mit einer geeigneten API vorzuziehen. Python hat ein jsonModul dafür, das ich persönlich häufig in meinen Skripten verwende, und es ist ziemlich einfach, die gewünschten Felder zu extrahieren:

$ python -c 'import sys,json;print json.load(sys.stdin)["buildStatus"]["status"]' <  input.txt
ERROR

Was hier passiert, ist, dass wir die Eingabedatei zu Pythons Standard umleiten und das mit lesen json.load(). Das wird ein Python-Wörterbuch mit dem Schlüssel "buildStatus" und es enthält ein anderes Python-Wörterbuch mit dem Schlüssel "status". Wir drucken also lediglich den Wert eines Schlüssels in einem Wörterbuch aus, der in einem anderen Wörterbuch gespeichert ist. Ziemlich Einfach.

Abgesehen von der Einfachheit ist ein weiterer Vorteil, dass Python und diese API alle vorinstalliert sind und standardmäßig mit Ubuntu geliefert werden.

Sergiy Kolodyazhnyy
quelle
6

Sie können dies in der Tat tun sed, aber ich rate Ihnen dringend, eine ausgefeiltere Sprache zu verwenden, die Tools für die Verarbeitung von JSON-Daten enthält. Sie könnten zum Beispiel Perl oder Python ausprobieren.

Nun, in Ihrem einfachen Beispiel, ist alles, was Sie wollen, das erste Vorkommen von "status", also können Sie Folgendes tun:

$ sed -nE '/status/{s/.*:\s*"(.*)",/\1/p;q}' file.json 
ERROR

Der Trick besteht darin -n, das Drucken zu vermeiden. Wenn die Linie mit status( /status/) übereinstimmt , entfernen Sie alles außer dem gewünschten Teil s/.*:\s*"(.*)",/\1/, pdrucken die Linie und schließen sie q.


Persönlich finde ich diesen äquivalenten grep-Befehl viel einfacher:

$ grep -m1 -oP '"status"\s*:\s*"\K[^"]+' file.json 
ERROR

Oder dieses:

$ perl -ne 'if(s/.*"status"\s*:\s*"([^"]+).*/$1/){print;exit}' file.json 
ERROR

Im Ernst, wenn Sie vorhaben, JSON-Dateien zu analysieren, versuchen Sie dies nicht manuell. Verwenden Sie einen richtigen JSON-Parser.

terdon
quelle
oder dieses:grep -m 1 status file.json | tr -cd '[[:alnum:]]:' | cut -f2 -d':'
slowko
1
@ user1876040 Gern geschehen. Bitte denken Sie daran, eine der Antworten zu akzeptieren (ich empfehle ByteCommander , da dies eine bessere Lösung ist), damit die Frage als beantwortet markiert werden kann.
Terdon
6

Nicht sagen , Sie sollten verwenden sed(Ich glaube , jemand Downvoted mich gerade für nicht obligatorisch Vorbehalt zu schreiben) , aber, wenn Sie etwas auf der suchen müssen nächste Zeile , buildStatuswie Sie scheinen in Ihrem eigenen Versuch zu versuchen, Sie sagen müssen sedlesen die nächste Zeile mit dem NBefehl

$ sed -rn '/buildStatus/N;s/.*buildStatus.*\n.*: "(.*)",/\1/p' file
ERROR

Anmerkungen:

  • -n drucke nichts aus, bis wir danach fragen
  • -rbenutze ERE (wie -E)
  • /buildStatus/N Finde dieses Muster und lies auch die nächste Zeile
  • s/old/new/ersetzen oldmitnew
  • .* Beliebige Anzahl beliebiger Zeichen in der Zeile
  • \n Neue Zeile
  • : "(.*)",Speichern Sie alle Zeichen zwischen : "und",
  • \1 Rückverweis auf gespeichertes Muster
  • p Drucken Sie den Teil, an dem wir gearbeitet haben
Zanna
quelle
0

Es gibt eine typische Erklärung dafür, warum sedund ähnliche Textstrom-Verarbeitungstools nicht gut dafür geeignet sind, strukturierte Daten wie JSON und XML zu analysieren. Ich habe das nicht zur Hand, aber es ist da draußen, und ich glaube, der Punkt ist, dass die Ausdrücke, die in allen, aber wahrscheinlich in den wenigsten Situationen benötigt werden, schnell sehr komplex werden, während alternative Tools, die speziell zum Analysieren der Struktur entwickelt wurden, komplexer sind elegant, lesbar und effizient bei der gleichen Analyse.

Wie muru in einem Kommentar formuliert hat , jqsollte das das richtige Werkzeug für den Job sein. Ich kann auch dafür bürgen, dass es persönlich sehr aufgeregt ist, wenn ich sehe, dass es mehrere Male ersetzt wird, wenn ich versucht habe, die gleichen Daten zu analysieren, ohne fast keinen oder belastenden Erfolg. Es enthält sogar umfangreiche Funktionen zum Formatieren und anderweitigen Steuern der Ausgabe. Ich bevorzuge es jsontoolaus einem oder mehreren Gründen, die ich derzeit vergesse.

Byte Commander scheint jshonin einer anderen Antwort zu empfehlen . Ich habe dieses Tool nicht benutzt, aber es erinnert mich an xmlstarletund seine Syntax, auch mit einer anpassbaren Präsentation für die Ausgabe.

Pysis
quelle
Sie sprechen wahrscheinlich von stackoverflow.com/a/1732454/2072269
muru
3
jsontool
Erwägen
Lol @muru, richtig, das ist einer der Posts, die versuchen, die Verwendung von XML / JSON mit Regex zu verhindern! Ich empfehle eher, jqdass muru und heemayl beschreiben, dass es bereits Beispiele gibt, und schreibe einfach die Gründe
Pysis
0

Nur ein weiteres Json-Tool namens json ( https://github.com/trentm/json )

$ json buildStatus.status < file.json
ERROR

Diese Fallstudie ist irreführend: Es sieht so aus, als würden Werkzeuge nicht funktionieren. Sie können auch jsonzum Ändern von JSON-Dateien Folgendes verwenden:

$ json -e 'this.buildStatus.status="not error"' < file.json > new.json

oder auch...

$ json -e 'this.buildStatus.status="no errors"' < file.json | json -e 'this.buildStatus.status
no errors

Dokumentation unter: http://trentm.com/json/


wenn nicht installiert:

  • Installieren Sie den Knoten
  • und sudo npm install -g json

quelle