it-swarm.com.de

So extrahieren Sie Daten aus einer JSON-Datei

Ich habe eine Lösung für meine Frage gesucht, aber keine gefunden oder besser gesagt, ich habe sie nicht mit dem bekommen, was ich gefunden habe. Sprechen wir also darüber, worum es bei meinem Problem geht. Ich verwende eine Smart Home Control-Software auf einem Raspberry Pi und wie ich an diesem Wochenende mithilfe von Pilight-Receive herausgefunden habe, kann ich die Daten von meinem Außentemperatursensor abrufen. Die Ausgabe von pilight-receive sieht folgendermaßen aus:

{
        "message": {
                "id": 4095,
                "temperature": 409.5
        },
        "Origin": "receiver",
        "protocol": "alecto_wsd17",
        "uuid": "0000-b8-27-eb-0f3db7",
        "repeats": 3
}
{
        "message": {
                "id": 1490,
                "temperature": 25.1,
                "humidity": 40.0,
                "battery": 1
        },
        "Origin": "receiver",
        "protocol": "alecto_ws1700",
        "uuid": "0000-b8-27-eb-0f3db7",
        "repeats": 3
}
{
        "message": {
                "id": 2039,
                "temperature": 409.5
        },
        "Origin": "receiver",
        "protocol": "alecto_wsd17",
        "uuid": "0000-b8-27-eb-0f3db7",
        "repeats": 4
}

Nun meine Frage an Sie: Wie zum Teufel kann ich die Temperatur und Luftfeuchtigkeit von der ID 1490 ermitteln. Und wie würden Sie mir empfehlen, dies regelmäßig zu überprüfen? Durch einen Cron-Job, der alle 10 Minuten ausgeführt wird, wird eine Ausgabe des Pilight-Empfangs erstellt, die Daten der Ausgabe extrahiert und an die Smart Home Control-API übertragen.

Jemand, der eine Idee hat - vielen Dank

13

Sie können jq verwenden, um JSON-Dateien in Shell zu verarbeiten.

Zum Beispiel habe ich Ihre Beispiel-JSON-Datei als raul.json Gespeichert und dann ausgeführt:

$ jq .message.temperature raul.json 
409.5
25.1
409.5
$ jq .message.humidity raul.json 
null
40
null

jq ist für die meisten Linux-Distributionen vorgepackt verfügbar.

Es gibt wahrscheinlich eine Möglichkeit, dies in jq selbst zu tun, aber die einfachste Möglichkeit, beide gewünschten Werte in einer Zeile abzurufen, ist die Verwendung von xargs. Zum Beispiel:

$ jq 'select(.message.id == 1490) | .message.temperature, .message.humidity' raul.json | xargs
25.1 40

wenn Sie jede .message.id - Instanz durchlaufen möchten, können Sie der Ausgabe .message.id hinzufügen und xargs -n 3 verwenden, da wir wissen, dass drei Felder (ID, Temperatur) vorhanden sind , Feuchtigkeit):

jq '.message.id, .message.temperature, .message.humidity' raul.json | xargs -n 3
4095 409.5 null
1490 25.1 40
2039 409.5 null

Sie können diese Ausgabe dann mit awk oder was auch immer nachbearbeiten.


Schließlich verfügen sowohl python als auch Perl über hervorragende Bibliotheken zum Parsen und Bearbeiten von JSON-Daten. Ebenso wie mehrere andere Sprachen, einschließlich PHP und Java.

23
cas

Mein bevorzugtes Tool für die Verarbeitung von JSON in der Befehlszeile ist jq. Wenn Sie jq jedoch nicht installiert haben, können Sie mit Perl ziemlich gut umgehen:

# Perl -MJSON -e '$/ = undef; my $data = <>; for my $hash (new JSON->incr_parse($data)) { my $msg = $hash->{message}; print "$msg->{temperature} $msg->{humidity}\n" if $msg->{id} == 1490 }' < data.json
25.1 40
0
nwk

Für diejenigen, die fortgeschrittene awk nicht so gut verstehen, wie sie möchten (wie Leute wie ich) und jq nicht vorinstalliert haben, wäre eine einfache Lösung Rohrleitungen ein paar native Befehle zusammen wie folgt:

grep -A2 '"id": 1490,' stats.json | sed '/1490/d;s/"//g;s/,//;s/\s*//'

Wenn Sie nur versuchen, die Werte zu erhalten, ist es einfacher, nur grep zu verwenden, als awk oder sed :

grep -A2 '"id": 1490,' stats.json | grep -o "[0-9]*\.[0-9]*"

Um eine Erklärung zu geben, scheint mir dies der einfachste Weg zu sein.

  • Der grep -A2 Erfasst die Zeile, nach der Sie im JSON suchen, zusammen mit den folgenden 2 Zeilen, die die Temperatur und Luftfeuchtigkeit enthalten.
  • Die Pipe zu grep -o Gibt einfach nur numerische Ziffern aus, die durch . Getrennt sind (was in der ersten Zeile 1490 Niemals vorkommt, sodass Sie Ihre 2 Werte - Temperatur - behalten und Luftfeuchtigkeit. Sehr einfach. Noch einfacher als die Verwendung von jq, meiner Meinung nach.
0
rubynorails

ihre Ausgabe besteht aus einer Reihe von JSON-Snippets und nicht aus einem vollständigen JSON. Wenn/sobald Sie Ihre Ausgabe so umstellen, dass sie ein integraler JSON ist, z. so (vorausgesetzt, Ihre Ausgabe ist in file.json):

echo "[ $(cat file.json | sed -E 's/^}$/},/; $d') }]"

dann ist es einfach, mit dem Tool jtc das zu erreichen, was Sie wollen (verfügbar unter: https://github.com/ldn-softdev/jtc ):

bash $ echo "[ $(cat file.json | sed -E 's/^}$/},/; $d') }]" | jtc -x "[id]:<1490>d [-1]" -y[temperature] -y[humidity] -l
"temperature": 25.1
"humidity": 40.0
bash $ 

im obigen Beispiel drop -l wenn Sie keine gedruckten Etiketten möchten

0
Dmitry L.

jq ist bei weitem die eleganteste Lösung. Mit awk können Sie schreiben

awk -v id=1490 '
    $1 == "\"id\":" && $2 == id"," {matched = 1}
    $1 == "}," {matched = 0}
    matched && $1 ~ /temperature|humidity/ {sub(/,/,"", $2); print $2}
' file
0
glenn jackman