Como extrair dados de um arquivo JSON

9

Eu tenho um bin pesquisando uma solução para a minha pergunta, mas não encontrei um, ou melhor, disse que não consegui com o que encontrei. Então vamos falar sobre o meu problema. Estou usando um software Smart Home Control em um Raspberry Pi e, como descobri neste fim de semana usando pilight-receive, posso pegar os dados do meu sensor de temperatura externo. A saída do pilight-receive é assim:

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

Agora, minha pergunta para você: Como diabos eu posso extrair a temperatura e a umidade de onde o id é 1490. E como você recomendaria que eu checasse isso com frequência? Por um cron job que executa a cada 10 minutos, cria uma saída do pilight-receive, extrai os dados da saída e os envia para o Smart Home Control Api.

Alguém que tenha uma ideia - muito obrigado

    
por Raul Garcia Sanchez 16.11.2015 / 22:26

5 respostas

17

Você pode usar jq para processar arquivos json no shell.

Por exemplo, salvei seu arquivo json de amostra como raul.json e, em seguida, executei:

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

jq está disponível pré-empacotado para a maioria das distribuições linux.

Provavelmente, existe uma maneira de fazer isso em jq , mas a maneira mais simples que encontrei para obter os dois valores desejados em uma linha é usar xargs . Por exemplo:

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

ou, se você quiser percorrer cada instância de .message.id , podemos adicionar .message.id à saída e usar xargs -n 3 , pois sabemos que haverá três campos (id, temperatura, umidade):

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

Você pode pós-processar essa saída com o awk ou o que for.

Finalmente, tanto o python quanto o perl possuem excelentes bibliotecas para analisar e manipular os dados do json. Assim como várias outras linguagens, incluindo php e java.

    
por 16.11.2015 / 23:11
0

jq é de longe a solução mais elegante. Com awk você poderia escrever

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

Para aqueles que não entendem o awk avançado como gostariam (como pessoas como eu) e não têm o jq pré-instalado, uma solução fácil seria canalizar alguns comandos nativos juntos assim:

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

Se você está apenas tentando obter os valores, é mais fácil usar apenas grep em vez de awk ou sed :

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

Para fornecer uma explicação, esta parece ser a maneira mais simples para mim.

  • O grep -A2 pega a linha que você está procurando no JSON junto com as duas linhas a seguir, que contêm a temperatura e a umidade.
  • O pipe para grep -o simplesmente imprime apenas dígitos numéricos separados por . (o que nunca ocorrerá na primeira linha 1490 , então você fica com seus 2 valores - temperatura e umidade. Muito simples. Ainda mais simples do que usar jq , na minha opinião.
por 17.11.2015 / 03:43
0

Minha ferramenta de escolha para processar JSON na linha de comando é jq. No entanto, se você não tiver o jq instalado, você pode se sair muito bem com o 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
    
por 18.11.2015 / 22:56
0

sua saída é um conjunto de snippets JSON, em vez de um JSON completo. Se / uma vez você reorganizar sua saída para ser um JSON integral, por exemplo assim (assumindo que sua saída está em file.json ):

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

é fácil alcançar o que você deseja com a ferramenta jtc (disponível em: link ):

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 $ 

no exemplo acima, elimine -l se não quiser etiquetas impressas

    
por 12.11.2018 / 18:47