JSON menguraikan shell

11

Bagaimana saya bisa melewatkan output JSON pada shell?

Misalnya, Amazon Web Services menyediakan CLI untuk mengambil status mesin virtual Anda:

$ aws ec2 describe-instances <my_instance_id>

Tetapi perintah mengembalikan string JSON. Output dari perintah itu terlihat seperti ini:

$ aws ec2 describe-instances x12345
{
    "Reservations" :
     {  
            "OwnerId": "1345345"
            "Groups": [], 
            "SecurityGroups": [
               {
                  "Foo" : "yes"
                  "Bar" : "no
               }
             ]
     }
}

Apakah ada built-in shell yang dapat digunakan untuk mem-parsing output JSON?

Sebagai contoh, saya ingin menangkap dalam variabel shell FOO, berikut ini output["Reservations"]["SecurityGroups"][0]{"Foo"}.

Jika itu membantu, saya secara khusus tertarik pada solusi yang dapat bekerja dari Zsh.

Amelio Vazquez-Reina
sumber
2
Anda biasanya akan menggunakan alat, seperti jshon .
jasonwryan
1
Gunakan --output textjika Anda ingin mengurai shell tanpa menggunakan alat eksternal seperti jshon.
jordanm
1
@jasonwryan - Baru saja mendengar jshonuntuk pertama kalinya, saya mengikuti tautan Anda. Setelah membaca itu, saya hanya bisa mengatakan bahwa saya pergi dengan sangat senang bahwa, kebetulan, saya mendengar dan menginstalnya jqterlebih dahulu. Saya pikir Anda mungkin ingin mendengarnya juga jika Anda belum - itu tidak mengganggu dengan semua saklar baris perintah dan dapat melakukan regex sendiri - bahkan memungkinkan Anda untuk mendeklarasikan fungsi dan variabel jika Anda mau. Lihat jawabannya di sini tentang hal itu jika Anda tertarik.
mikeserv

Jawaban:

10

Seperti yang saya pahami, Anda mencari nilai "Foo". Ini sangat mudah dilakukan dengan alat baris perintah shell jq. Itu adalah sesuatu seperti seddi mana ia mengimplementasikan jenis bahasa pengurai sendiri. Diberikan contoh Anda:

json='
{
    "Reservations" :
     {  
            "OwnerId" : "1345345",
            "Groups" :  [],
            "SecurityGroups" : [
               {
                  "Foo" : "yes",
                  "Bar" : "no"
               }
             ]
     }
}'

jqbisa yesdengan mudah:

printf %s "$json" |
jq '.[].SecurityGroups[0].Foo?'                                                

KELUARAN

"yes"

Anda dapat berjalan melalui hash objek atau daftar kamus menggunakan .dotnotasi, dan array yang diindeks dapat diindeks lebih sederhana, dengan, karena Anda mungkin menebak, numerik, indeks kurung siku. Dalam perintah di atas saya menggunakan formulir indeks kosong untuk menunjukkan bahwa saya ingin semua item yang dapat diubah tingkat itu diperluas. Itu mungkin lebih mudah dipahami dengan cara ini:

printf %s "$json" | jq '.[][]'

... yang membagi semua nilai untuk item tingkat kedua di hash dan membuat saya ...

"1345345"
[]
[
  {
    "Foo": "yes",
    "Bar": "no"
  }
]

Ini nyaris tidak menggores permukaan sehubungan dengan jqkemampuan. Ini adalah alat yang sangat kuat untuk membuat serialisasi data di shell, ini mengkompilasi ke biner tunggal yang dapat dieksekusi dalam gaya Unix klasik, sangat mungkin tersedia melalui manajer paket untuk distribusi Anda, dan itu didokumentasikan dengan sangat baik. Silahkan kunjungi nya git-Page dan lihat sendiri.

Omong-omong, cara lain untuk menangani data berlapis json- setidaknya untuk mendapatkan ide tentang apa yang Anda kerjakan - mungkin dengan cara lain dan menggunakan .dotnotasi untuk membagi semua nilai di semua tingkatan seperti:

printf %s "$json" | jq '..'

{
  "Reservations": {
    "OwnerId": "1345345",
    "Groups": [],
    "SecurityGroups": [
      {
        "Foo": "yes",
        "Bar": "no"
      }
    ]
  }
}
{
  "OwnerId": "1345345",
  "Groups": [],
  "SecurityGroups": [
    {
      "Foo": "yes",
      "Bar": "no"
    }
  ]
}
"1345345"
[]
[
  {
    "Foo": "yes",
    "Bar": "no"
  }
]
{
  "Foo": "yes",
  "Bar": "no"
}
"yes"
"no"

Tetapi jauh lebih baik, mungkin, hanya akan menggunakan salah satu dari banyak metode penemuan atau pencarian yang jqmenawarkan berbagai jenis node.

mikeserv
sumber
10

Ini adalah jawaban untuk tujuan Anda, tetapi bukan pertanyaan Anda. Berarti Anda dapat mencapai tujuan Anda tanpa menggunakan parser JSON.

Pemanfaatan AWS memiliki kemampuan untuk hanya output bidang pilih menggunakan --queryargumen. Ini didokumentasikan di sini .

Sebagai contoh:

$ aws ec2 describe-instances \
  --query 'Reservations[0].Instances[0].SecurityGroups[0].GroupName' \
  --instance-id i-6b272337 \
  --output text
mongodb

Anda bahkan dapat memilih beberapa bidang jika ingin:

$ aws ec2 describe-instances \
  --query 'Reservations[0].Instances[0].SecurityGroups[0].[GroupName,GroupId]' \
  --instance-id i-6b272337 \
  --output text
mongodb sg-710ffa14

Dan Anda juga dapat menampilkan beberapa struct yang cocok:

$ aws ec2 describe-instances \
  --query 'Reservations[0].Instances[0].SecurityGroups[*].[GroupName,GroupId]' \
  --instance-id i-6b272337 \
  --output text
mongodb sg-710ffa14
default sg-a0243bcc
Patrick
sumber
1
Terima kasih! Itu sangat membantu. Saya menerima @mikeserv sebagian besar untuk melayani komunitas dengan jawaban atas pertanyaan, tetapi jawaban Anda adalah yang akan saya gunakan
Amelio Vazquez-Reina
Ini sangat membantu! Terima kasih banyak!!
MD Sayem Ahmed