Як розібрати JSON з сценарієм оболонки в Linux?


56

У мене є вихід JSON, з якого мені потрібно витягти кілька параметрів в Linux.

Це вихід JSON:

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

Я хочу написати файл, який містить заголовок типу ідентифікатора екземпляра, тег, як ім’я, центр витрат, власник. і нижче, ніж певні значення на виході JSON. Наведений тут результат - лише приклад.

Як я можу це зробити за допомогою sedта awk?

Очікуваний вихід:

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

1
Створіть ваш CLI-дзвінок у python, запропонований, оскільки він є рідним для EC2. Python може легко інтерпретувати JSON. Дивіться відповідь нижче для прикладу. Звичайно, ви також можете використовувати будь-яку іншу мову SS, але вони вимагають встановлення, тоді як Python вже є.
Роббі Аверилл

Відповіді:


65

Наявність парсерів майже в кожній мові програмування є однією з переваг JSON як формату обміну даними.

Замість того, щоб намагатися реалізувати аналізатор JSON, вам, швидше за все, краще скористатися або інструментом, побудованим для розбору JSON, таким як jq, або загальною мовою сценарію, що має бібліотеку JSON.

Наприклад, використовуючи jq, ви можете витягнути ImageID з першого елемента масиву інстанцій таким чином:

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

Крім того, щоб отримати ту саму інформацію, використовуючи бібліотеку JSON Ruby:

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

Я не відповім на всі ваші переглянуті питання та зауваження, але, мабуть, наступного, сподіваємось, для початку роботи.

Припустимо, у вас був сценарій Ruby, який міг прочитати a зі STDIN та вивести другий рядок у вашому прикладі виводу [0]. Цей сценарій може виглядати приблизно так:

#!/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}"

Як ви могли використовувати такий сценарій для досягнення всієї своєї мети? Ну, припустимо, у вас уже було таке:

  • команда перелічити всі ваші екземпляри
  • команда отримати json вище для будь-якого примірника зі свого списку та вивести його в STDOU

Одним із способів було б використовувати оболонку для комбінування цих інструментів:

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

Тепер, можливо, у вас є одна команда, яка дає вам один json blob для всіх екземплярів з більшою кількістю елементів у цьому масиві "Примірники". Ну, якщо це так, вам просто потрібно буде трохи змінити сценарій, щоб повторити його через масив, а не просто використовувати перший елемент.

Зрештою, спосіб вирішити цю проблему - це спосіб вирішити багато проблем в Unix. Розбийте його на більш легкі проблеми. Знайдіть або запишіть інструменти для вирішення простішої проблеми. Поєднайте ці інструменти з оболонкою або іншими функціями операційної системи.

[0] Зауважте, що я поняття не маю, звідки ви дістаєте центр витрат, тому я щойно це склав.


я встановив jq на своїй машині. але я не знаю, як отримати інформацію. я поновлюю питання
user3086014

Як це зробити. команда ec2-описуючий примірник дає такі кадри. це дані для 1 екземпляра, є 100 екземплярів. Як це зробити у сценарії
користувач3086014

У мене є Aws Клі інструменти, який дає мені вихід. тепер, як проаналізувати вихідний і потрібні теги, про які я дійсно не знаю
user3086014

2
@ user3086014 Вибачте, але більше не буду вкладати більше робіт у цю відповідь. Погляньте на приклад Рубі, який у мене є. Це повинно дати вам гарне місце, щоб розпочати те, як вибирати теги з різних частин потрібного JSON.
Стівен Д

Наближеність інструментів json, доступних jq, є моїм улюбленим stedolan.github.io/jq/manual . Доступний і в std-дистрибуції. Ігровий майданчик для тестування фільтрів доступний на веб-
lrkwz

15

Ви можете використовувати наступний скрипт python для аналізу цих даних. Давайте припустимо , що у вас є дані в форматі JSON з масивів в файлах , таких як array1.json, array2.jsonі так далі.

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()

А потім просто запустіть:

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

Я не бачив вартості у ваших даних, тому я не включав їх.

Відповідно до обговорення в коментарях, я оновив сценарій parse.py:

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"] 

Ви можете спробувати виконати таку команду:

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

але це лише один масив, є схожі масиви, повернуті командою. як це зробити
user3086014

і ці дані генеруються командою екземпляра, що описує ec2, під час виконання. як впоратися з цим
користувач3086014

Я трохи змінив цей скрипт python: 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() Якщо у вас є всі дані json з масивів у таких файлах, як array1.json, array2.json, ... і так далі, ви можете спробувати запустити його так: # for x in ls * .json; do python parse.py $x; done
Robert Йончі

ви можете оновити відповідь. не читабельно
користувач3086014

також у мене є масиви.100 таких масивів
user3086014

9

Наступний код jq:

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

використовується як:

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

виведе:

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

Кілька покажчиків на розуміння коду:

  • from_entriesприймає масив об'єктів типу {key:a, value:b}і перетворює його в об'єкт з відповідними парами ключ / значення ( {a: b});
  • Ці Keyта Valueключі в Tagsмасиві повинні були бути перетворені в нижньому регістрі;
  • Останній рядок використовує функцію інтерполяції рядків jq. Ви можете налаштувати його за потребою.

Для отримання більш детальної інформації див. Підручник та посібник jq на веб-сторінці https://stedolan.github.io/jq/


1
Тепер ви можете скоротити вилучення тегів за допомогою (.Tags | map({Value, Key}) | from_entries) as $tags, не перетворюючи ключі в малі регістри.
mloughran

8

Інші надали загальні відповіді на ваше запитання, які демонструють хороші способи розбору json, проте я, як і ви, шукав спосіб вилучити ідентифікатор екземпляра aws за допомогою основного інструменту, як awk або sed, не залежно від інших пакетів. Для цього ви можете передати аргумент "--output = text" вашій команді aws, яка дасть вам строко простежувану рядок. З цим ви можете просто отримати ідентифікатор екземпляра, використовуючи щось на зразок наступного ...

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

3

Jshon випускається в декількох дистрибутивах:

$ 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

Погане пояснення: -e uuвитягуватиме об’єкт uu, -aзробить масив корисним (не впевнений, що я правильно сформулював цей, але все одно ...), -uрозшифрує рядок, -pповернеться до попереднього елемента (здається, що -i NN, будь-яке число, має той же ефект) .

Залежно від вашого випадку, висновок може потребувати певного лікування (наприклад, як ви бачите).

Jshon не здається надійним щодо мальформації JSON (ваші "Теги" з комами перед закритою фігурною дужкою призведуть до помилки).

Хтось згадав джейдж в іншій нитці, але я не перевіряв його.



0

Ось пропозиція з одного вкладиша:

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)

Не ідеально, але це би спрацювало, якщо трохи підправити його.

В основному це використовується prдля друку кожного результату на кожен стовпець. Кожен набір результатів повертається методом підстановки, який аналізує файл JSON та повертає значення на основі ключа.

Це працює так, як описано в: З огляду на вміст ключових значень, як я групую значення за ключем і сортуйте за значенням?


0

Погляньте на jtcінструмент cli:

це дозволяє легко витягувати потрібну інформацію з вашого json (якщо припустити, що вона є file.json, btw, ваш JSON потрібно виправити, там є кілька додаткових коми):

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 на щось читабельне, як це:

{
  "версія": [
    "sessionrestore",
    1
  ],
  "windows": [
    {
      "вкладки": [
        {
          "записи": [
            {
              "url": "http://orf.at/#/stories/2.../",
              "title": "news.ORF.at",
              "charset": "UTF-8",
              "Ідентифікатор": 9588,
              "docshellID": 298,
              "docIdentifier": 10062,
              "зберігатись": правда
            },
...

Тепер має бути можливість аналізувати ваші дані будь-якими стандартними інструментами

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.