JSON Linux'ta kabuk komut dosyasıyla nasıl ayrıştırılır?


56

Linux'ta birkaç parametre çıkarmam gereken bir JSON çıkışım var.

Bu JSON çıktısıdır:

{
        "OwnerId": "121456789127",
        "ReservationId": "r-48465168",
        "Groups": [],
        "Instances": [
            {
                "Monitoring": {
                    "State": "disabled"
                },
                "PublicDnsName": null,
                "RootDeviceType": "ebs",
                "State": {
                    "Code": 16,
                    "Name": "running"
                },
                "EbsOptimized": false,
                "LaunchTime": "2014-03-19T09:16:56.000Z",
                "PrivateIpAddress": "10.250.171.248",
                "ProductCodes": [
                    {
                        "ProductCodeId": "aacglxeowvn5hy8sznltowyqe",
                        "ProductCodeType": "marketplace"
                    }
                ],
                "VpcId": "vpc-86bab0e4",
                "StateTransitionReason": null,
                "InstanceId": "i-1234576",
                "ImageId": "ami-b7f6c5de",
                "PrivateDnsName": "ip-10-120-134-248.ec2.internal",
                "KeyName": "Test_Virginia",
                "SecurityGroups": [
                    {
                        "GroupName": "Test",
                        "GroupId": "sg-12345b"
                    }
                ],
                "ClientToken": "VYeFw1395220615808",
                "SubnetId": "subnet-12345314",
                "InstanceType": "t1.micro",
                "NetworkInterfaces": [
                    {
                        "Status": "in-use",
                        "SourceDestCheck": true,
                        "VpcId": "vpc-123456e4",
                        "Description": "Primary network interface",
                        "NetworkInterfaceId": "eni-3619f31d",
                        "PrivateIpAddresses": [
                            {
                                "Primary": true,
                                "PrivateIpAddress": "10.120.134.248"
                            }
                        ],
                        "Attachment": {
                            "Status": "attached",
                            "DeviceIndex": 0,
                            "DeleteOnTermination": true,
                            "AttachmentId": "eni-attach-9210dee8",
                            "AttachTime": "2014-03-19T09:16:56.000Z"
                        },
                        "Groups": [
                            {
                                "GroupName": "Test",
                                "GroupId": "sg-123456cb"
                            }
                        ],
                        "SubnetId": "subnet-31236514",
                        "OwnerId": "109030037527",
                        "PrivateIpAddress": "10.120.134.248"
                    }
                ],
                "SourceDestCheck": true,
                "Placement": {
                    "Tenancy": "default",
                    "GroupName": null,
                    "AvailabilityZone": "us-east-1c"
                },
                "Hypervisor": "xen",
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda",
                        "Ebs": {
                            "Status": "attached",
                            "DeleteOnTermination": false,
                            "VolumeId": "vol-37ff097b",
                            "AttachTime": "2014-03-19T09:17:00.000Z"
                        }
                    }
                ],
                "Architecture": "x86_64",
                "KernelId": "aki-88aa75e1",
                "RootDeviceName": "/dev/sda1",
                "VirtualizationType": "paravirtual",
                "Tags": [
                    {
                        "Value": "Server for testing RDS feature in us-east-1c AZ",
                        "Key": "Description"
                    },
                    {
                        "Value": "RDS_Machine (us-east-1c)",
                        "Key": "Name"
                    },
                    {
                        "Value": "1234",
                        "Key": "cost.centre",
                      },
                    {
                        "Value": "Jyoti Bhanot",
                        "Key": "Owner",
                      }
                ],
                "AmiLaunchIndex": 0
            }
        ]
    }

Örnek kimliği, etiket adı, maliyet merkezi, sahibi gibi başlık içeren bir dosya yazmak istiyorum. ve bunun altında JSON çıkışındaki belirli değerler. Burada verilen çıktı sadece bir örnek.

Nasıl kullanarak da yapabilirsiniz sedve awk?

Beklenen çıktı :

 Instance id         Name                           cost centre             Owner
    i-1234576          RDS_Machine (us-east-1c)        1234                   Jyoti

1
EC2 örneklerine özgü olduğundan CLI çağrınızı python'a aktarın. Python JSON'u kolayca yorumlayabilir. Örnek için aşağıdaki cevaba bakınız. Tabii ki, diğer SS dillerini de kullanabilirsiniz, ancak Python zaten oradayken, kurulum gerektireceklerdir.
Robbie Averill

Yanıtlar:


65

Hemen hemen her programlama dilinde ayrıştırıcıların bulunması, JSON'un veri değişim formatı olarak avantajlarından biridir.

Bir JSON ayrıştırıcısı uygulamaya çalışmak yerine, jq gibi bir JSON ayrıştırması için oluşturulmuş bir araç veya JSON kitaplığına sahip genel amaçlı bir komut dosyası dili kullanmaktan daha iyi bir olasılık elde edersiniz .

Örneğin, jq kullanarak, ImageID'i Örnekler dizisinin ilk öğesinden aşağıdaki gibi çıkarabilirsiniz:

jq '.Instances[0].ImageId' test.json

Alternatif olarak, Ruby'nin JSON kütüphanesini kullanarak aynı bilgiyi almak için:

ruby -rjson -e 'j = JSON.parse(File.read("test.json")); puts j["Instances"][0]["ImageId"]'

Tüm gözden geçirilmiş soru ve yorumlarınıza cevap vermeyeceğim, ancak aşağıdakiler başlamanız için yeterli olacaktır.

STDIN'den okuyabilen ve ikinci çıktıyı örnek çıktınızda [0] çıkaran bir Ruby komut dosyanız olduğunu varsayalım. Bu senaryo şuna benzeyebilir:

#!/usr/bin/env ruby
require 'json'

data = JSON.parse(ARGF.read)
instance_id = data["Instances"][0]["InstanceId"]
name = data["Instances"][0]["Tags"].find {|t| t["Key"] == "Name" }["Value"]
owner = data["Instances"][0]["Tags"].find {|t| t["Key"] == "Owner" }["Value"]
cost_center = data["Instances"][0]["SubnetId"].split("-")[1][0..3]
puts "#{instance_id}\t#{name}\t#{cost_center}\t#{owner}"

Tüm hedefinize ulaşmak için böyle bir senaryoyu nasıl kullanabilirsiniz? Diyelim ki zaten aşağıdakilere sahipsin:

  • tüm örneklerinizi listeleme komutu
  • json'u listenizdeki herhangi bir örnek için almak ve STDOU’ya göndermek için bir komut

Bunun bir yolu, kabuğunuzu bu araçları birleştirmek için kullanmak olacaktır:

echo -e "Instance id\tName\tcost centre\tOwner"
for instance in $(list-instances); do
    get-json-for-instance $instance | ./ugly-ruby-scriptrb
done

Şimdi, belki de o "Örnekler" dizisindeki daha fazla öğeye sahip tüm örnekler için size bir json blob veren tek bir komutunuz vardır. Durum buysa, yalnızca ilk öğeyi kullanmak yerine diziyi yinelemek için komut dosyasını biraz değiştirmeniz gerekir.

Sonunda, bu sorunu çözmenin yolu, Unix'te birçok sorunu çözmenin yoludur. Daha kolay sorunlara bölün. Kolay sorunu çözmek için araçlar bulun veya yazın. Bu araçları kabuğunuzla veya diğer işletim sistemi özellikleriyle birleştirin.

[0] Unutmayın ki, nereden maliyet merkezi elde edeceğinize dair bir fikrim yok, o yüzden yeni yaptım.


Makineme jq yükledim. ama nasıl bilgi alacağımı bilmiyorum. Ben soruyu güncelleştiriyorum
user3086014

Bu nasıl yapılır. ec2-example komutunu bu şekilde verir. Bu 1 örnek için veri, 100 örnek var. Bir komut dosyasında bunu nasıl
user3086014

Bana çıktı veren aws cli araçları var. Şimdi çıktıyı ve gerçekten bilmiyorum gerekli etiketleri nasıl ayrıştırılacağını
user3086014

2
@ user3086014 Üzgünüm, ama bu cevaba daha fazla iş koymayacağım. Orada sahip olduğum Ruby örneğine bir bak. İstediğiniz JSON'un çeşitli bölümlerinden etiketlerin nasıl çıkarılacağına başlamak için size iyi bir yer sağlamalıdır.
Steven D

Json araçlarının moltitüdünde jq en sevdiğim stedolan.github.io/jq/manual . Std dağılımında da mevcuttur. Filtreleri test etmek için bir oyun alanı mevcuttur jqplay.org/jq?q=.&j=%22Hello%2C%20world!%22
lrkwz

15

Bu verileri ayrıştırmak için aşağıdaki python betiğini kullanabilirsiniz. Diyelim ki JSON verilerinin array1.json, array2.jsonvb.

import json
import sys
from pprint import pprint

jdata = open(sys.argv[1])

data = json.load(jdata)

print "InstanceId", " - ", "Name", " - ", "Owner"
print data["Instances"][0]["InstanceId"], " - " ,data["Instances"][0]["Tags"][1]["Value"], " - " ,data["Instances"][0]["Tags"][2]["Value"] 

jdata.close()

Ve sonra sadece koş:

$ for x in `ls *.json`; do python parse.py $x; done
InstanceId  -  Name  -  Owner
i-1234576  -  RDS_Machine (us-east-1c)  -  Jyoti Bhanot

Verilerinizde maliyet görmedim, bu yüzden bunu dahil etmedim.

Yorumlardaki tartışmaya göre, parse.py komut dosyasını güncelledim:

import json
import sys
from pprint import pprint

jdata = sys.stdin.read()

data = json.loads(jdata)

print "InstanceId", " - ", "Name", " - ", "Owner"
print data["Instances"][0]["InstanceId"], " - " ,data["Instances"][0]["Tags"][1]["Value"], " - " ,data["Instances"][0]["Tags"][2]["Value"] 

Aşağıdaki komutu çalıştırmayı deneyebilirsiniz:

#ec2-describe-instance <instance> | python parse.py

fakat bu sadece bir dizidir, komut tarafından döndürülen benzer diziler vardır. bu nasıl yapılır
user3086014 27:14

ve bu veriler çalışma zamanında ec2-example example komutu ile üretilir. bunun nasıl kullanılacağı
user3086014 27:14

Bu python betiğini biraz değiştirdim: import json from pprint import pprint jdata = open('example.json') data = json.load(jdata) print "InstanceId", " - ", "Name", " - ", "Owner" print data["Instances"][0]["InstanceId"], " - " ,data["Instances"][0]["Tags"][1]["Value"], " - " ,data["Instances"][0]["Tags"][2]["Value"] jdata.close() Dizi dizilerindeki tüm json verilerinizi array1.json, array2.json, ... vb. Gibi dosyalarda varsa, bu şekilde çalıştırmayı deneyebilirsiniz: # for x in ls * .json; do python parse.py $x; done
Robert Jonczy

cevabın kendisini güncelleyebilirsiniz. okunabilir değil
user3086014

ayrıca böyle dizilerde diziler.100 var
user3086014

9

Aşağıdaki jq kodu:

.Instances[] | (.Tags | map(.value=.Value | .key=.Key) | from_entries) as $tags | "\(.InstanceId) | \($tags.Name) | \($tags["cost.centre"]) | \($tags.Owner)"

gibi kullanılan:

json_producer | jq -r '<jq code...>'

çıktı:

i-1234576 | RDS_Machine (us-east-1c) | 1234 | Jyoti Bhanot

Kodu anlamak için birkaç işaretçi:

  • from_entriesgibi {key:a, value:b}bir nesne dizisi alır ve karşılık gelen anahtar / değer çiftleriyle bir nesneye dönüştürür ( {a: b});
  • Dizideki Keyve Valuetuşlarının Tagsküçük harfe dönüştürülmesi gerekiyordu;
  • Son dize, jq'nin string enterpolasyon özelliğini kullanır. Gerektiği gibi ince ayar yapabilirsiniz.

Daha fazla ayrıntı için, https://stedolan.github.io/jq/ adresindeki jq öğreticisinin kılavuzuna bakın.


1
Artık, (.Tags | map({Value, Key}) | from_entries) as $tagstuşları küçük harfe dönüştürmeden etiketlerin çıkarılmasını kısaltabilirsiniz .
mloughran

8

Diğerleri, sorunuza json'u ayrıştırmanın iyi yollarını gösteren genel cevaplar verdiler, ancak ben de sizin gibi, diğer paketlere bağlı olmadan awk veya sed gibi bir çekirdek aracı kullanarak bir aws örnek kimliği çıkarmanın bir yolunu arıyordum. Bunu başarmak için, "--output = text" argümanını aws komutunuza, awk ayrıştırılabilir bir dize verecek şekilde iletebilirsiniz. Bununla sadece aşağıdaki gibi bir şey kullanarak örnek kimliğini alabilirsiniz ...

aws ec2 run-instances --output text  | awk -F"\t" '$1=="INSTANCES" {print $8}'

3

Jshon birkaç dağıtımda mevcuttur:

$ echo your_JSON|jshon -e Instances -a -e InstanceId -u -p -e Tags -a -e Key -u -p -e Value -u
i-1234576
Description
Server for testing RDS feature in us-east-1c AZ
Name
RDS_Machine (us-east-1c)
cost.centre
1234
Owner
Jyoti Bhanot

Kötü açıklama: -e uunesne elde edecek uu, -a(Ben doğru ... Bu bir phrased ama yine de emin değilim) dizi kullanışlı hale getirecek -u, dize deşifre edecek -pönceki öğeye geri döner (görünüyor -i NN herhangi bir sayı olan aynı etkiye sahiptir,) .

Davanıza bağlı olarak, çıktı bir miktar işlem sonrası gerektirebilir (sizin görebildiğiniz gibi sizinki gibi).

Jshon JSON malformasyonuna karşı sağlam görünmese de, (kapanış kıvrık parantezinden önce virgül içeren "Etiketler" iniz bir hataya neden olur).

Birisi başka bir iş parçacığında jsawk'tan bahsetti , ancak test etmedim.



0

İşte bir liner öneri:

pr -mt \
 <(grep -o ".*: .*," in.json | grep -iw InstanceId | cut -d: -f2) \
 <(grep -o ".*: .*," in.json | grep -iw Value      | cut -d: -f2) \
 <(grep -o ".*: .*," in.json | grep -iw Key        | cut -d: -f2)

Mükemmel değil, ama biraz değiştirirseniz işe yarar.

prHer sütun için sonuç setini yazdırmak için kullanılır . Her sonuç seti JSON dosyasını ayrıştıran ve anahtara dayalı değerler döndüren işlem değişikliği ile döndürülür.

Bu, aşağıda açıklandığı şekilde çalışır: Anahtar-değer içeriği göz önüne alındığında, değerleri anahtarla nasıl gruplayabilir ve değere göre nasıl sıralayabilirim?


0

jtcCli aracına bir göz atın :

json'unuzdan gerekli bilgilerin kolayca çıkarılmasını sağlar (içinde olduğu varsayılarak file.json, btw, JSON'unuzun sabitlenmesi gerekiyor, orada birkaç tane virgül var):

bash $ cat file.json | jtc -x '<InstanceId>l+0[-1]' -y '[InstanceId]' -y "[Key]:<Name>[-1][Value]" -y "[Key]:<cost.centre>[-1][Value]" -y "[Key]:<Owner>[-1][Value]" | sed 's/"/\\"/g' | xargs -L4 echo
"i-1234576" "RDS_Machine (us-east-1c)" "1234" "Jyoti Bhanot"
bash $ 

-2

jq "." recovery.js | head -n 20

jason dosyanızı aşağıdaki gibi okunabilir bir şeye çevirir:

{
  "sürüm": [
    "Sessionrestore",
    1
  ],
  "pencereler": [
    {
      "sekmeler": [
        {
          "girdileri": [
            {
              "url": "http://orf.at/#/stories/2.../",
              "title": "news.ORF.at",
              "karakter kümesi": "UTF-8",
              "Kimlik": 9588,
              "docshellID": 298,
              "doküman tanımlayıcı": 10062,
              "kalıcı": doğru
            },
...

Artık verilerinizi herhangi bir standart araçla ayrıştırmanız mümkün olmalıdır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.