Как проанализировать 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
user3086014
источник
1
Направьте ваш вызов CLI в python, потому что он является родным для экземпляров EC2. Python может легко интерпретировать JSON. Смотрите ответ ниже для примера. Конечно, вы также можете использовать любой другой язык SS, но они потребуют установки, тогда как Python уже существует.
Робби Аверилл
как насчет использования узла ?
Элиран Малка

Ответы:

65

Наличие синтаксических анализаторов практически на каждом языке программирования является одним из преимуществ JSON как формата обмена данными.

Вместо того, чтобы пытаться реализовать анализатор JSON, вам, скорее всего, лучше использовать инструмент, созданный для анализа JSON, такой как jq, или язык сценариев общего назначения с библиотекой JSON.

Например, используя jq, вы можете извлечь ImageID из первого элемента массива Instances следующим образом:

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

Кроме того, чтобы получить ту же информацию, используя библиотеку JSON в Ruby:

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

Я не буду отвечать на все ваши исправленные вопросы и комментарии, но надеюсь, что следующего достаточно, чтобы вы начали.

Предположим, что у вас есть скрипт на Ruby, который может читать из 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-description дает результат следующим образом. это данные для 1 экземпляра, есть 100 экземпляров. Как это сделать в скрипте
user3086014
У меня есть инструменты AWS Cli, что дает мне вывод. Теперь, как проанализировать вывод и необходимые теги, которые я действительно не знаю
user3086014
2
@ user3086014 Извините, но я не буду больше работать над этим ответом. Взгляните на пример Ruby, который у меня есть. Это должно дать вам хорошее место для начала о том, как получить теги из различных частей 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-description во время выполнения. как с этим справиться
user3086014
Я немного изменил этот скрипт на 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 Jonczy
Вы можете обновить ответ сам. его не читается
user3086014
также у меня есть массивы .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/.

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

Другие предоставили общие ответы на ваш вопрос, которые демонстрируют хорошие способы синтаксического анализа json, однако я, как и вы, искал способ извлечь идентификатор экземпляра aws, используя основной инструмент, такой как awk или sed, без зависимости от других пакетов. Для этого вы можете передать аргумент «--output = text» в вашу команду aws, которая даст вам строку, доступную для анализа awk. При этом вы можете просто получить идентификатор экземпляра, используя что-то вроде следующего ...

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-ошибкам (ваши «теги» с запятыми перед закрывающей фигурной скобкой вызовут ошибку).

Кто-то упомянул jsawk в другой ветке, но я его не проверял.

Скиппи ле Гран Гуру
источник
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 и возвращает значения на основе ключа.

Это работает аналогично тому, как описано в разделе : При заданном содержании значения ключа, как сгруппировать значения по ключу и отсортировать по значению?

kenorb
источник
0

Взгляните на jtcинструмент Cli:

он позволяет легко извлекать необходимую информацию из вашего json (при условии, что он находится file.json, кстати, ваш 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
  ],
  "окна": [
    {
      "вкладки": [
        {
          "записи": [
            {
              "url": "http://orf.at/#/stories/2.../",
              "title": "news.ORF.at",
              "charset": "UTF-8",
              «ID»: 9588,
              «docshellID»: 298,
              «docIdentifier»: 10062,
              "сохраняться": правда
            },
...

Теперь должна быть возможность проанализировать ваши данные с помощью любых стандартных инструментов.

Ternitz
источник