如何在Linux中使用Shell脚本解析JSON?


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

我想编写一个包含标题(如实例ID),标签(如名称,成本中心,所有者)的文件。并低于JSON输出中的某些值。此处给出的输出仅是示例。

我该如何使用sedawk呢?

预期产量:

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

1
建议将CLI调用通过管道传递到python,这是因为它是EC2实例的本机。Python可以轻松解释JSON。有关示例,请参见下面的答案。当然,您也可以使用任何其他SS语言,但是它们需要安装,而Python已经存在。
罗比·阿夫里尔

Answers:


65

几乎每种编程语言都可以使用解析器,这是JSON作为数据交换格式的优点之一。

与其尝试实现JSON解析器,不如使用为JSON解析而构建的工具(例如jq)或具有JSON库的通用脚本语言,可能更好。

例如,使用jq,您可以从Instances数组的第一项中提取ImageID,如下所示:

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

另外,要使用Ruby的JSON库获取相同的信息,请执行以下操作:

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

我不会回答您所有的修改后的问题和评论,但希望以下内容足以帮助您入门。

假设您有一个Ruby脚本,可以从STDIN读取a并在示例输出[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中许多问题的方法。将其分解为更简单的问题。查找或编写工具来解决更简单的问题。将这些工具与您的Shell或其他操作系统功能结合使用。

[0]请注意,我不知道您从哪里获得成本中心,所以我只是弥补了这一点。


我已经在机器上安装了jq。但我不知道如何获取信息。我正在更新问题
2014年

怎么做。命令ec2-describe实例会像这样给出reslut。这是1个实例的数据,有100个实例。如何在脚本中执行此操作
2014年

我有aws cli工具,可以给我输出。现在如何解析输出和我真正不知道的必需标签
user3086014 2014年

2
@ user3086014对不起,但是我不会在这个答案上做更多的工作。看一下我那里的Ruby示例。它应该为您提供一个良好的起点,让您开始如何从所需的JSON各个部分中获取标签。
史蒂文D

在众多json工具中,jq是我最喜欢的stedolan.github.io/jq/manual。也可以在std发行版中使用。可在jqplay.org/jq?q=.&j=%22Hello%2C%20world!%22
lrkwz 2015年

15

您可以使用以下python脚本来解析该数据。假设您有来自文件(如array1.jsonarray2.json依此类推)中的数组的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 2014年

并且此数据由ec2-describe实例命令在运行时生成。如何处理
user3086014 2014年

我对这个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() 如果您从array1.json,array2.json等文件中的数组中获得了所有json数据,则可以尝试这样运行它: # for x in ls * .json; do python parse.py $x; done
Robert Jonczy 2014年

您可以自己更新答案。它不可读
user3086014 2014年

我也有arrays.100这样的数组
user3086014 2014年

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})的对象;
  • 数组中的KeyValueTags必须转换为小写;
  • 最后一个字符串使用jq的字符串插值功能。您可以根据需要进行调整。

有关更多详细信息,请参阅https://stedolan.github.io/jq/上的 jq教程和手册。


1
现在,您可以使用来缩短标签的提取(.Tags | map({Value, Key}) | from_entries) as $tags,而无需将键转换为小写。
mloughran'5

8

其他人则为您的问题提供了一般性答案,展示了解析json的好方法,但是像您一样,我一直在寻找一种方法,可以使用awk或sed之类的核心工具提取aws实例ID,而不依赖于其他软件包。为此,您可以将“ --output = text”参数传递给aws命令,这将为您提供awk可分析的字符串。这样,您可以简单地使用以下内容获取实例ID ...

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 N,N为任意数字,具有相同的效果) 。

根据您的情况,输出可能需要进行一些后处理(如您所见,就像您一样)。

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文件并根据键返回值。

它的工作方式与以下内容中所述类似:给定键值内容,如何按键对值进行分组并按值排序?


0

看看jtccli工具:

它可以轻松地从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个
  ],
  “窗户”:[
    {
      “标签”:[
        {
          “条目”:[
            {
              “ url”:“ http://orf.at/#/stories/2.../”,
              “ title”:“ news.ORF.at”,
              “ charset”:“ UTF-8”,
              “ ID”:9588,
              “ docshellID”:298,
              “ docIdentifier”:10062,
              “坚持”:真实
            },
...

现在应该可以使用任何标准工具解析数据了

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.