Como fazer um loop através do arquivo json?

6

Eu tenho um arquivo json abaixo e quero obter o hostId, somente se o name contiver algum valor específico. Eu quero usar o script de shell para conseguir isso.

{
  "items" : [ {
    "name" : "first-block-e70a2fe8fd0531ad1f87de49f03537a6",
    "type" : "STORE",
    "hostRef" : {
      "hostId" : "166219e3-be5c-46d0-b4c7-33543a29ce32"
    },
    "roleState" : "STARTED",
    "healthSummary" : "GOOD",

    },
  {
   "name" : "second-block-c21a1ae8dd2831cd1b87de49f98274e8",
    "type" : "STORE",
    "hostRef" : {
      "hostId" : "176429e3-be5c-46d0-b4c7-33543a29ad63"
    },
    "roleState" : "STARTED",
    "healthSummary" : "GOOD",
  }

  {
   "name" : "first-block-a85d2fe6fd0482ad1f54de49f45174a0",
    "type" : "STORE",
    "hostRef" : {
      "hostId" : "176429e3-ae1d-46d0-b4c7-66123a24fa82"
    },
    "roleState" : "STARTED",
    "healthSummary" : "GOOD",
  }

}

Por exemplo: se o nome contiver algo com 'primeiro bloco' então eu devo pegar o hosdId como

166219e3-be5c-46d0-b4c7-33543a29ce32
176429e3-ae1d-46d0-b4c7-66123a24fa82

Como posso percorrer o arquivo json? Qual regex devo usar para filtrar o elemento que contém algum valor específico em name e obter o hostid ?

    
por Alex Raj Kaliamoorthy 01.06.2016 / 21:10

6 respostas

2

Um exemplo muito simples usando python:

#!/usr/bin/env python

import sys
import json

def print_first(data):
    for item in data["items"]:
        if item["name"].startswith("first"):
            print item["hostRef"]["hostId"]

def main(argv):
    for json_file in argv:
        with open(json_file) as data_file:
            data = json.load(data_file)
            print_first(data)

if __name__ == "__main__":
    main(sys.argv[1:])

Isso é com seus dados de amostra re-formatados como:

{
    "items" : [
        {
            "name" : "first-block-e70a2fe8fd0531ad1f87de49f03537a6",
            "type" : "STORE",
            "hostRef" : {
                "hostId" : "166219e3-be5c-46d0-b4c7-33543a29ce32"
            },
            "roleState" : "STARTED",
            "healthSummary" : "GOOD"

        },
        {
            "name" : "second-block-c21a1ae8dd2831cd1b87de49f98274e8",
            "type" : "STORE",
            "hostRef" : {
                "hostId" : "176429e3-be5c-46d0-b4c7-33543a29ad63"
            },
            "roleState" : "STARTED",
            "healthSummary" : "GOOD"
        },
        {
            "name" : "first-block-a85d2fe6fd0482ad1f54de49f45174a0",
            "type" : "STORE",
            "hostRef" : {
                "hostId" : "176429e3-ae1d-46d0-b4c7-66123a24fa82"
            },
            "roleState" : "STARTED",
            "healthSummary" : "GOOD"
        }
    ]
}
    
por 01.06.2016 / 22:25
4

Você pode usar jq:

Arquivo de entrada:

{
  "items" : [
    {
      "name" : "first-block-e70a2fe8fd0531ad1f87de49f03537a6",
      "type" : "STORE",
      "hostRef" : {
        "hostId" : "166219e3-be5c-46d0-b4c7-33543a29ce32"
      },
      "roleState" : "STARTED",
      "healthSummary" : "GOOD"

    },
    {
      "name" : "second-block-c21a1ae8dd2831cd1b87de49f98274e8",
      "type" : "STORE",
      "hostRef" : {
        "hostId" : "176429e3-be5c-46d0-b4c7-33543a29ad63"
      },
      "roleState" : "STARTED",
      "healthSummary" : "GOOD"
    },

    {
      "name" : "first-block-a85d2fe6fd0482ad1f54de49f45174a0",
      "type" : "STORE",
      "hostRef" : {
        "hostId" : "176429e3-ae1d-46d0-b4c7-66123a24fa82"
      },
      "roleState" : "STARTED",
      "healthSummary" : "GOOD"
    }
  ]
}
comando

:

Editar: com a contribuição do @ Runium

$ jq '.items[] | select( .name | startswith("first-block-"))|.hostRef.hostId' < file.json 
"e70a2fe8fd0531ad1f87de49f03537a6"
"a85d2fe6fd0482ad1f54de49f45174a0"
    
por 01.06.2016 / 22:24
1

jq já foi mencionado algumas vezes, por isso mencionarei jsonpipe . Ele converte json data em um formato orientado a linha adequado para processamento com ferramentas de comando como grep , sed , awk , perl , etc. É uma ferramenta de linha de comando para trabalhar com json em um shell e uma biblioteca python.

Por exemplo, se seus dados json de amostra forem salvos em um arquivo chamado alex.json e, em seguida, editados para que seja realmente válido json:

$ jsonpipe < alex.json 
/   {}
/items  []
/items/0    {}
/items/0/name   "first-block-e70a2fe8fd0531ad1f87de49f03537a6"
/items/0/type   "STORE"
/items/0/hostRef    {}
/items/0/hostRef/hostId "166219e3-be5c-46d0-b4c7-33543a29ce32"
/items/0/roleState  "STARTED"
/items/0/healthSummary  "GOOD"
/items/1    {}
/items/1/name   "second-block-c21a1ae8dd2831cd1b87de49f98274e8"
/items/1/type   "STORE"
/items/1/hostRef    {}
/items/1/hostRef/hostId "176429e3-be5c-46d0-b4c7-33543a29ad63"
/items/1/roleState  "STARTED"
/items/1/healthSummary  "GOOD"
/items/2    {}
/items/2/name   "first-block-a85d2fe6fd0482ad1f54de49f45174a0"
/items/2/type   "STORE"
/items/2/hostRef    {}
/items/2/hostRef/hostId "176429e3-ae1d-46d0-b4c7-66123a24fa82"
/items/2/roleState  "STARTED"
/items/2/healthSummary  "GOOD"

Você poderia então canalizá-lo para o awk para extrair qualquer coisa que pareça um hostId no segundo campo do intervalo começando com o padrão / primeiro bloco / e terminando com / hostId /.

$ jsonpipe < alex.json  | 
    awk '/first-block/,/hostId/ {
             if ($2 ~ /\"[a-f0-9]{8}-/) {
                 gsub(/\"/,"",$2);
                 print $2
             }
         }'
166219e3-be5c-46d0-b4c7-33543a29ce32
176429e3-ae1d-46d0-b4c7-66123a24fa82

BTW, você pode obter jsonpipe output no formato "paragraph", com cada "item" em um parágrafo separado, colocando-o em sed . por exemplo. Nesse caso, adicione uma nova linha antes de cada registro de item.

$ jsonpipe < alex.json | 
    sed -e 's/\/items\/[[:digit:]]\+[[:blank:]]\+/\n&/'
/   {}
/items  []

/items/0    {}
/items/0/name   "first-block-e70a2fe8fd0531ad1f87de49f03537a6"
/items/0/type   "STORE"
/items/0/hostRef    {}
/items/0/hostRef/hostId "166219e3-be5c-46d0-b4c7-33543a29ce32"
/items/0/roleState  "STARTED"
/items/0/healthSummary  "GOOD"

/items/1    {}
/items/1/name   "second-block-c21a1ae8dd2831cd1b87de49f98274e8"
/items/1/type   "STORE"
/items/1/hostRef    {}
/items/1/hostRef/hostId "176429e3-be5c-46d0-b4c7-33543a29ad63"
/items/1/roleState  "STARTED"
/items/1/healthSummary  "GOOD"

/items/2    {}
/items/2/name   "first-block-a85d2fe6fd0482ad1f54de49f45174a0"
/items/2/type   "STORE"
/items/2/hostRef    {}
/items/2/hostRef/hostId "176429e3-ae1d-46d0-b4c7-66123a24fa82"
/items/2/roleState  "STARTED"
/items/2/healthSummary  "GOOD"

Dados separados por parágrafos são um formato muito comum, e ferramentas comuns como awk e sed e perl 1 têm recursos que facilitam o trabalho com parágrafos. Além disso, há muitos exemplos desse tipo de trabalho facilmente encontrados neste e em outros sites de SE, assim como no google.

Finalmente, jsonpipe tem uma contraparte jsonunpipe para converter este formato simples orientado para a linha de volta para json.

Por exemplo, se você quiser nivelar a estrutura para que hostId seja uma propriedade de um item em vez de em hostRef:

$ jsonpipe < alex.json  | 
      sed -e '/hostRef[[:blank:]]/d;s/hostRef\///' |
      jsonunpipe
{"items": [{"name": "first-block-e70a2fe8fd0531ad1f87de49f03537a6", "type": "STORE", "hostId": "166219e3-be5c-46d0-b4c7-33543a29ce32", "roleState": "STARTED", "healthSummary": "GOOD"}, {"name": "second-block-c21a1ae8dd2831cd1b87de49f98274e8", "type": "STORE", "hostId": "176429e3-be5c-46d0-b4c7-33543a29ad63", "roleState": "STARTED", "healthSummary": "GOOD"}, {"name": "first-block-a85d2fe6fd0482ad1f54de49f45174a0", "type": "STORE", "hostId": "176429e3-ae1d-46d0-b4c7-66123a24fa82", "roleState": "STARTED", "healthSummary": "GOOD"}]}

Se necessário, você pode canalizar isso por jq ou json_pp ou similar a pretty-print para legibilidade humana.

1 perl tem vários módulos excelentes para analisar e manipular dados do json, então é melhor você usar um deles. Sempre que você estiver lendo dados de grep , sed e / ou awk em perl , você realmente deve se perguntar "Por que estou fazendo isso? Isso é loucura, eu deveria fazer a coisa toda em perl" . O mesmo pode ser dito para python .

    
por 02.06.2016 / 07:12
0

Como @Theophrastus mencionou, você deseja instalar o analisador JSON jq primeiro. Depois disso, é apenas uma questão de filtrar o valor desejado.

Eu devo mencionar que o bloco JSON que você postou não é válido; o colchete de abertura de "itens" não está fechado e a segunda entrada em items deve ter um separador de vírgula. Apesar disso, vou assumir que você tem um bloco válido e apenas recortou e colou o que achava relevante. Se cada bloco é realmente representativo, então tudo o que você precisa adicionar é (assumindo que bash é seu shell)

echo "${YOUR_JSON_BLOCK}"  |  jq '.items[].hostRef.hostId'

Isso produzirá apenas aquelas linhas, conforme especificado, supondo que YOUR_JSON_BLOCK seja a string json válida com seus dados.

    
por 01.06.2016 / 22:22
0

Recentemente eu criei uma alternativa unix / shell mais fácil (é inteiramente FOSS e gratuita) para lidar com consultas json como essa - dê uma olhada em jtc . A ferramenta permite lidar com caminhadas relativas (ou seja, encontrar uma e depois se deslocar para outra).

assumindo que o seu json original é fixo (tem alguns problemas), então o cli seria assim:

bash $ cat file.json | jtc -w'[name]:<^first-block>R: [-1] [hostRef] [hostId]'
"166219e3-be5c-46d0-b4c7-33543a29ce32"
"176429e3-ae1d-46d0-b4c7-66123a24fa82"
bash $ 
    
por 22.01.2019 / 11:10
0

[Outra abordagem jq] Se você usar jq , isso é literalmente um forro!

cat input.json | jq -r '.["items"] | map(select(.name | contains("first-block"))) | .[].hostRef.hostId'

P.S.

  1. Os comandos jq são bastante autoexplicativos, portanto, não estou tentando explicá-lo ainda, se alguém estiver enfrentando dificuldades, deixe-me saber nos comentários, eu explicarei!

  2. O json fornecido na pergunta não está completo!

por 14.03.2019 / 17:28

Tags