Cách trích xuất dữ liệu từ tệp JSON


13

Tôi có bin tìm kiếm một giải pháp cho câu hỏi của mình nhưng không tìm thấy hay nói tốt hơn là tôi không hiểu nó với những gì tôi tìm thấy. Vì vậy, hãy nói về những gì vấn đề của tôi là về. Tôi đang sử dụng Phần mềm điều khiển nhà thông minh trên Raspberry Pi và khi tôi phát hiện ra vào cuối tuần này bằng cách sử dụng pilight-receive, tôi có thể bắt dữ liệu từ cảm biến nhiệt độ ngoài trời của mình. Đầu ra của pilight-receive trông như thế:

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

Bây giờ câu hỏi của tôi cho bạn: Làm thế nào tôi có thể trích xuất nhiệt độ và độ ẩm từ nơi id là 1490. Và làm thế nào bạn có thể khuyên tôi nên kiểm tra điều này thường xuyên? Bằng một công việc định kỳ chạy cứ sau 10 phút, tạo ra đầu ra của pilight-receive, trích xuất dữ liệu của đầu ra và đẩy nó vào Api Smart Home Control.

Ai đó có một ý tưởng - cảm ơn rất nhiều


3
Định dạng dường như là JSON . Có rất nhiều cách để phân tích JSON. Nó phụ thuộc vào những gì bạn cảm thấy thoải mái. Con trăn? JavaScript? Thứ gì khác?
muru

Tôi biết một chút Python và một chút JavaScript chủ yếu là tôi biết C ++ và C #. Nhưng sau khi thấy tất cả các lệnh awk và sed, tôi phải là một lệnh dễ dàng xD
Raul Garcia Sanchez

1
Không khó awksedcung cấp đầu ra JSON vẫn giữ định dạng được hiển thị ở đây, điều này không cần - khoảng trắng không quan trọng đối với JSON. Ví dụ, awklệnh này : awk '/temperature|humidity/ {print $2}'gần.
muru

4
với ksh93phân tích cú pháp json được tích hợp vào read.
mikeerv

1
kiểm tra hậu trường khò khè. nó có thể ở trong đó, tiết kiệm cho bạn một bản nâng cấp lên jessie (trừ khi bạn dự định nâng cấp bằng mọi cách). aha nó được báo trước để khò khè. packages.debian.org/wheezy-backports/jq
cas

Câu trả lời:


22

Bạn có thể dùng jq để xử lý các tệp json trong shell.

Ví dụ: tôi đã lưu tệp json mẫu của bạn raul.jsonvà sau đó chạy:

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

jq có sẵn được đóng gói sẵn cho hầu hết các bản phân phối linux.

Có lẽ có một cách để tự làm điều đó jq, nhưng cách đơn giản nhất tôi tìm thấy để có được cả hai giá trị mong muốn trên một dòng là sử dụng xargs. Ví dụ:

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

hoặc, nếu bạn muốn lặp qua từng .message.idtrường hợp, chúng ta có thể thêm .message.idvào đầu ra và sử dụng xargs -n 3vì chúng ta biết rằng sẽ có ba trường (id, nhiệt độ, độ ẩm):

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

Sau đó, bạn có thể xử lý hậu kỳ đầu ra với awk hoặc bất cứ điều gì.


Cuối cùng, cả python và perl đều có thư viện tuyệt vời để phân tích và thao tác dữ liệu json. Cũng như một số ngôn ngữ khác, bao gồm php và java.


2
cụ thể,jq 'select(.message.id == 1490) | .message.temperature, .message.humidity' raul.json
glenn jackman

1
hoặc, trong bash,{ read temp; read hum; } < <(jq ...)
glenn jackman

1
Xem câu trả lời của tôi mà chỉ đơn giản là sử dụng grep. Nó có thể không hoạt động đối với một số phiên bản cụ thể grep, nhưng nó đơn giản hơn jqtrong kịch bản này, mặc dù jqđược thiết kế đặc biệt để phân tích cú pháp JSON. Tôi đã đưa ra jqcâu trả lời mặc dù, bất kể. Nó thực sự là một công cụ cho công việc, nhưng đôi khi bạn có thể chỉ cần tháo ghim bằng ngón tay thay vì tìm kiếm xung quanh để tìm một dụng cụ tháo ghim.
rubynorails

2
json không thể được phân tích cú pháp một cách đáng tin cậy bằng các biểu thức thông thường nhiều hơn xml hoặc html có thể. và hầu hết dữ liệu json (ví dụ: được tìm nạp qua api web) không được định dạng độc đáo với nguồn cấp dữ liệu bổ sung và thụt dòng. để phân tích json một cách đáng tin cậy, bạn cần một trình phân tích cú pháp json. jqlà một trong những kịch bản shell. các ngôn ngữ khác có thư viện phân tích json.
cas

1
bất cứ điều gì có thể được phân tích cú pháp đáng tin cậy với các biểu thức thông thường. nó chỉ phụ thuộc vào số lượng bạn sử dụng. bạn nghĩ jqthế nào
mikeerv

0

jqcho đến nay là giải pháp thanh lịch nhất. Với awkbạn có thể viết

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

0

Đối với những người không hiểu nâng cao awkcũng như họ muốn (chẳng hạn như những người như tôi) và không jqđược cài đặt sẵn, một giải pháp dễ dàng sẽ là kết hợp một vài lệnh gốc với nhau như vậy:

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

Nếu bạn chỉ đang cố gắng để có được các giá trị, việc sử dụng grepthay vì awkhoặc sed:

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

Để cung cấp một lời giải thích, đây dường như là cách đơn giản nhất với tôi.

  • Dòng này grep -A2lấy dòng bạn đang tìm kiếm trong JSON cùng với 2 dòng sau, có chứa nhiệt độ và độ ẩm.
  • Đường ống grep -ochỉ đơn giản chỉ in các chữ số được phân tách bằng một .(sẽ không bao giờ xảy ra trên 1490dòng đầu tiên , do đó, bạn chỉ còn lại 2 giá trị - nhiệt độ và độ ẩm. Rất đơn giản jq.

0

Công cụ tôi chọn để xử lý JSON trên dòng lệnh là jq. Tuy nhiên, nếu bạn chưa cài đặt jq, bạn có thể làm khá tốt với 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

đầu ra của bạn là một tập hợp các đoạn JSON chứ không phải là một JSON hoàn chỉnh. Nếu / một khi bạn sắp xếp lại đầu ra của mình thành một JSON không thể tách rời, ví dụ như thế này (giả sử đầu ra của bạn ở trong file.json):

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

sau đó thật dễ dàng để đạt được những gì bạn muốn với jtccông cụ (có sẵn tại: 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 $ 

trong ví dụ trên thả -lnếu bạn không muốn in nhãn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.