JSON dosyasından veri ayıklama


13

Sorum için bir çözüm arama bin var ama bir ya da daha iyi bulamadık buldum ile alamadım dedi. Şimdi sorunumun ne hakkında olduğunu konuşalım. Raspberry Pi'de Akıllı Ev Kontrol Yazılımı kullanıyorum ve bu hafta sonu pilight-rece kullanarak öğrendiğim gibi, dış sıcaklık sensörümden veri yakalayabilirim. Pilight alma özelliği şöyle görünür:

{
        "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
}

Şimdi size sorum: Kimliğin 1490 olduğu yerden sıcaklık ve nemi nasıl çıkarabilirim? Bunu sık sık kontrol etmemi nasıl önerirsiniz? Her 10 dakikada bir çalışan, pilight alımının bir çıktısını oluşturan, çıkışın verilerini ayıklayan ve Smart Home Control Api'ye ileten bir cron işi ile.

Bir fikri olan biri - çok teşekkürler


3
Biçim JSON gibi görünüyor . JSON'u ayrıştırmanın birçok yolu vardır. Ne ile rahat olduğuna bağlıdır. Python? JavaScript? Başka bir şey?
muru

Python ve JavaScript biraz biliyorum çoğunlukla C ++ ve C # biliyorum. Ama tüm awk ve sed komutlarını gördükten sonra ben bazı kolay komut xD olmalı
Raul Garcia Sanchez

1
JSON çıktısının burada gösterilen biçimlendirmeyi sürdürmesi gerekmediği awkve gerektirmemesi zor seddeğildir - boşluk JSON için önemli değildir. Örneğin, şu awkkomut: awk '/temperature|humidity/ {print $2}'yakın.
muru

4
ile ksh93json ayrıştırma yerleşiktir read.
mikeserv

1
wheezy-backport'ları kontrol edin. orada olabilir, (yine de yükseltmeyi planlamıyorsanız) jessie için bir yükseltme kaydetme. Aha! hırıltılıdır. Packages.debian.org/wheezy-backports/jq
cas

Yanıtlar:


23

jqKabuktaki json dosyalarını işlemek için kullanabilirsiniz .

Örneğin, örnek json dosyanızı olarak kaydettik raul.jsonve daha sonra çalıştırdım:

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

jq çoğu linux dağıtım için önceden paketlenmiştir.

Muhtemelen jqkendi başına yapmanın bir yolu vardır , ancak her iki istenen değeri bir satırda elde etmenin en basit yolu kullanmaktır xargs. Örneğin:

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

veya her bir .message.idörnekte döngü yapmak istiyorsanız .message.id, çıktıya ekleyebilir ve xargs -n 3üç alan (id, sıcaklık, nem) olacağını bildiğimiz gibi kullanabiliriz :

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

Daha sonra bu çıktıyı awk veya başka bir yöntemle sonradan işleyebilirsiniz.


Son olarak, hem python hem de perl json verilerini ayrıştırmak ve değiştirmek için mükemmel kütüphanelere sahiptir. Php ve java gibi diğer bazı diller gibi.


2
özellikle,jq 'select(.message.id == 1490) | .message.temperature, .message.humidity' raul.json
glenn jackman

1
veya, bash,{ read temp; read hum; } < <(jq ...)
glenn jackman

1
Sadece kullanan cevabımı görün grep. Bazı özel sürümleri için çalışmayabilir grep, ancak JSON ayrıştırmak için özel olarak tasarlanmış jqolsa da jq, bu senaryodan daha basittir . Ne jqolursa olsun , cevabı bir oylama verdim. Gerçekten iş için bir araçtır, ancak bazen zımba sökücü aramak yerine parmaklarınızla zımbaları çıkarabilirsiniz.
rubynorails

2
json, xml veya html'den daha fazla düzenli ifadelerle güvenilir bir şekilde ayrıştırılamaz. ve çoğu json verisi (örneğin, bir web API'sı aracılığıyla getirilir), fazladan satır beslemeleri ve girintiyle iyi biçimlendirilmez. json'u güvenilir bir şekilde ayrıştırmak için bir json ayrıştırıcısına ihtiyacınız var. jqkabuk betikleri için böyle bir şeydir. diğer diller json ayrıştırma kütüphanelerine sahiptir.
cas

1
her şey düzenli ifadelerle güvenilir şekilde ayrıştırılabilir. sadece kaç tane kullandığınıza bağlı. nasıl düşünüyorsun jq?
mikeserv

0

jqen zarif çözüm. Seninle awkyazabilirsin

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

0

Gelişmişliği anlamadıkları awkkadar istedikleri (benim gibi insanlar gibi) ve jqönceden yüklenmemiş olanlar için kolay bir çözüm, birkaç yerel komutu bir araya getirmek olacaktır:

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

Yalnızca değerleri almaya çalışıyorsanız veya grepyerine şunu kullanmak daha kolaydır :awksed

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

Bir açıklama yapmak için, bu benim için en basit yol gibi görünüyor.

  • grep -A2Eğer sıcaklık ve nem ihtiva aşağıdaki 2 hat ile birlikte JSON aradığınız hattını yakalar.
  • grep -oSadece bir ile ayrılmış sayısal basamakları basacak boru .(ilk 1490satırda asla gerçekleşmeyecek , bu nedenle 2 değerlerinizle kaldınız - sıcaklık ve nem. Çok basit. Kullanmaktan bile daha basit jq, bence.

0

Komut satırında JSON işlemek için tercih ettiğim araç jq. Ancak, jq yüklü değilse Perl ile oldukça iyi yapabilirsiniz:

# 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

çıktınız tam bir JSON yerine bir dizi JSON snippet'idir. Çıktınızı ayrılmaz bir JSON olarak yeniden düzenlediğinizde / örneğin, bunun gibi (çıktınızın olduğu varsayılarak file.json):

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

jtcaraçla istediğinizi elde etmek kolaydır (şu adreste bulunabilir: 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 $ 

-lbasılı örnek istemiyorsanız yukarıdaki örnekte

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.