Як отримати дані з файлу JSON


13

Я шукаю рішення для свого запитання, але не знайшов або, краще сказати, не отримав його з тим, що знайшов. Тож давайте поговоримо про те, у чому полягає моя проблема. Я використовую програмне забезпечення Smart Home Control на Raspberry Pi, і, як я дізнався ці вихідні, використовуючи pilight-прийом, я можу отримати дані з мого датчика зовнішньої температури. Вихід pilight-отримання виглядає так:

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

Тепер моє запитання до вас: як, до біса, я можу отримати температуру та вологість повітря з місця, де 1490. І як би ви порадили мені це часто перевіряти? Завданням cron, яке виконується кожні 10 хвилин, створює висновок прийому, що надходить, витягує дані виводу та передає їх у Smart Home Control Api.

Хтось має ідею - велике спасибі


3
Формат, здається, JSON . Існує маса способів розбору JSON. Це залежить від того, що вам подобається. Пітон? JavaScript? Щось ще?
муру

Я знаю трохи Python і трохи JavaScript, в основному я знаю C ++ і C #. Але побачивши всі команди awk і sed, я, мабуть, повинна бути легкою командою xD
Рауль Гарсія Санчес

1
Це не складно awkі за sedумови, що вихід JSON зберігає показане тут форматування, яке йому не потрібно - пробіл JSON не має значення. Наприклад, ця awkкоманда: awk '/temperature|humidity/ {print $2}'близько.
муру

4
з ksh93json синтаксичний розбір будується в read.
mikeserv

1
перевірити хрипкі спини. це може бути там, економивши вам оновлення до Джессі (якщо ви все-таки не планували оновлення). ага! це підтримується хрипом. packages.debian.org/wheezy-backports/jq
Cas

Відповіді:


23

Ви можете використовувати jqдля обробки файлів json у оболонці.

Наприклад, я зберегла ваш зразок файлу json як raul.jsonі запустила:

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

jq доступний заздалегідь упакованим для більшості дистрибутивів Linux.

Напевно, існує спосіб зробити це jqсам по собі, але найпростіший спосіб я знайшов обидва потрібні значення в одному рядку - це використовувати xargs. Наприклад:

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

або, якщо ви хочете провести цикл через кожен .message.idекземпляр, ми можемо додати .message.idдо виводу та використовувати, xargs -n 3оскільки ми знаємо, що буде три поля (id, температура, вологість):

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

Ви можете потім обробити цей висновок за допомогою awk чи будь-чого іншого.


Нарешті, і python, і perl мають відмінні бібліотеки для аналізу та обробки даних json. Як і кілька інших мов, включаючи php та java.


2
конкретно,jq 'select(.message.id == 1490) | .message.temperature, .message.humidity' raul.json
glenn jackman

1
або, в баш,{ read temp; read hum; } < <(jq ...)
glenn jackman

1
Дивіться мою відповідь, яка просто використовує grep. Він може не працювати в деяких конкретних версіях grep, але він є більш прямим, ніж jqу цьому сценарії, хоча jqвін розроблений спеціально для розбору JSON. Я jqвідповів, але незалежно від відповіді. Це справді інструмент для роботи, але іноді ви можете просто видалити скоби пальцями, а не шукати за допомогою засобу для зняття скоби.
rubynorails

2
json не може бути надійно розібраний з регулярними виразами більше, ніж може бути xml або html. і більшість даних json (наприклад, отримані через веб-api) не підходять до формату із додатковими стрічками та відступами. щоб надійно розібрати json, вам потрібен аналізатор json. jqє одним з таких сценаріїв оболонок. інші мови мають json для розбору бібліотек.
cas

1
все можна надійно проаналізувати регулярними виразами. це просто залежить від того, скільки ви використовуєте. як ви думаєте, jqяк це робиться?
mikeserv

0

jqна сьогоднішній день є найелегантнішим рішенням. З awkтобою можна було писати

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

0

Для тих, хто не розуміє просунутого awk, а так, як їм хотілося б (наприклад, таких як я) і не мають jqпопередньо встановлених програм, легким рішенням буде з’єднати пару натурних команд разом так:

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

Якщо ви тільки намагаєтеся отримати значення, це найпростіше з допомогою , grepа не awkчи sed:

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

Для пояснення це здається мені найпростішим способом.

  • grep -A2Захоплює лінію , яку ви шукаєте в форматі JSON разом з наступним 2 -х ліній, які містять температуру і вологість.
  • Труба grep -oпросто друкує лише цифрові цифри, розділені знаком .(який ніколи не відбудеться на першому 1490рядку, тому вам залишаються ваші 2 значення - температура та вологість. Дуже прості. На jqмою думку, навіть простіші, ніж використання .

0

Мій інструмент вибору для обробки JSON в командному рядку - jq. Однак якщо у вас не встановлено jq, ви можете дуже добре виконати Perl:

# 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

ваш вихід - це набір фрагментів JSON, а не повний JSON. Якщо / як тільки ви переставляєте свій вихід на інтегральний JSON, наприклад, як це (якщо виходите file.json)

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

тоді легко досягти того, що ви хочете за допомогою jtcінструменту (доступно за посиланням: 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 $ 

у наведеному вище прикладі випадайте, -lякщо ви не хочете друкувати етикетки

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.