JSON 파일에서 데이터를 추출하는 방법


13

나는 내 질문에 대한 해결책을 찾고있는 빈을 가지고 있지만 더 나은 것을 찾지 못했다. 내 문제에 대해 이야기 해 봅시다. Raspberry Pi에서 Smart Home Control Software를 사용하고 있으며 이번 주말에 pilight-receive를 사용하면 실외 온도 센서에서 데이터를 수집 할 수 있습니다. pilight-receive의 출력은 다음과 같습니다.

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

이제 당신에게 내 질문 : ID가 1490 인 곳에서 온도와 습도를 어떻게 추출 할 수 있습니까? 그리고 이것을 자주 확인하도록 어떻게 권장합니까? 10 분마다 실행되는 크론 작업에 의해, pilight-receive의 출력을 작성하고, 출력 데이터를 추출하여 Smart Home Control Api로 푸시합니다.

아이디어가있는 사람-많은 감사


3
형식은 JSON 인 것 같습니다 . JSON을 구문 분석하는 방법에는 여러 가지가 있습니다. 당신이 편한 것에 달려 있습니다. 파이썬? 자바 스크립트? 다른 것?
muru

나는 약간의 파이썬과 약간의 JavaScript를 알고 있으며 주로 C ++과 C #을 알고 있습니다. 그러나 모든 awk 및 sed 명령을 본 후에는 몇 가지 쉬운 명령 xD 일 것입니다.
Raul Garcia Sanchez

1
로 그것은 어렵지 않다 awksedjson으로 출력을 제공는 여기에 표시 서식을 유지하는 그것은 필요가 없다 - 공백 중요하지 않습니다 JSON하십시오. 예를 들어 다음 awk명령 awk '/temperature|humidity/ {print $2}'은 close입니다.
muru

4
ksh93json 구문 분석이 내장되어 read있습니다.
mikeserv

1
wheezy-backports를 확인하십시오. 어쨌든 업그레이드를 계획하지 않는 한 jessie 로의 업그레이드를 저장합니다. 아하! 그것은 희미하게 백 포트됩니다. 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
글렌 잭맨

1
또는 bash에서{ read temp; read hum; } < <(jq ...)
glenn jackman

1
단순히 사용하는 내 대답을 참조하십시오 grep. 의 특정 버전에서는 작동하지 않을 수 grep있지만 JSON 구문 분석을 위해 특별히 설계된 jq경우에도이 시나리오 보다 더 간단 jq합니다. 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대신 오히려 사용 하는 것이 더 쉽습니다 .awksed

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

설명을하기 위해 이것은 가장 간단한 방법 인 것 같습니다.

  • grep -A2당신이 온도와 습도를 포함하는 다음과 같은 2 개 라인과 함께 JSON에서 찾고있는 줄을 잡고.
  • 파이프는 grep -o단순히 .(첫 번째 1490줄에는 절대로 발생하지 않으므로 숫자와 숫자 만 인쇄 하므로 온도와 습도는 두 가지 값으로 남습니다. 매우 간단합니다. 심지어 사용하는 것보다 훨씬 간단 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인쇄 된 라벨을 원하지 않으면 위의 예에서 드롭

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.