Làm cách nào để phân tích JSON với shell scripting trong Linux?


56

Tôi có một đầu ra JSON mà tôi cần trích xuất một vài tham số trong Linux.

Đây là đầu ra 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
            }
        ]
    }

Tôi muốn viết một tệp chứa tiêu đề như id cá thể, thẻ như tên, trung tâm chi phí, chủ sở hữu. và dưới giá trị nhất định đó từ đầu ra JSON. Đầu ra ở đây đưa ra chỉ là một ví dụ.

Làm thế nào tôi có thể làm điều đó bằng cách sử dụng sedawk?

Sản lượng dự kiến:

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

1
Chuyển cuộc gọi CLI của bạn thành python, được đề xuất vì nó có nguồn gốc từ các phiên bản EC2. Python có thể dễ dàng giải thích JSON. Xem câu trả lời dưới đây cho một ví dụ. Tất nhiên, bạn cũng có thể sử dụng bất kỳ ngôn ngữ SS nào khác, nhưng chúng sẽ yêu cầu cài đặt trong khi Python đã có sẵn.
Robbie Averill

Làm thế nào về việc sử dụng nút ?
Eliran Malka

Câu trả lời:


65

Tính khả dụng của các trình phân tích cú pháp trong gần như mọi ngôn ngữ lập trình là một trong những lợi thế của JSON như một định dạng trao đổi dữ liệu.

Thay vì cố gắng triển khai trình phân tích cú pháp JSON, bạn có thể sử dụng một công cụ được xây dựng để phân tích cú pháp JSON như jq hoặc ngôn ngữ tập lệnh có mục đích chung có thư viện JSON.

Ví dụ: bằng cách sử dụng jq, bạn có thể rút ImageID từ mục đầu tiên của mảng Instances như sau:

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

Ngoài ra, để có được thông tin tương tự bằng thư viện JSON của Ruby:

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

Tôi sẽ không trả lời tất cả các câu hỏi và nhận xét sửa đổi của bạn, nhưng những điều sau đây hy vọng đủ để bạn bắt đầu.

Giả sử rằng bạn có một tập lệnh Ruby có thể đọc từ STDIN và xuất dòng thứ hai trong đầu ra ví dụ của bạn [0]. Kịch bản đó có thể trông giống như:

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

Làm thế nào bạn có thể sử dụng một kịch bản như vậy để thực hiện toàn bộ mục tiêu của bạn? Chà, giả sử bạn đã có những điều sau đây:

  • một lệnh để liệt kê tất cả các trường hợp của bạn
  • một lệnh để lấy json ở trên cho bất kỳ trường hợp nào trong danh sách của bạn và xuất nó thành STDOU

Một cách sẽ là sử dụng trình bao của bạn để kết hợp các công cụ này:

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

Bây giờ, có thể bạn có một lệnh duy nhất cung cấp cho bạn một json blob cho tất cả các trường hợp có nhiều mục hơn trong mảng "Trường hợp" đó. Chà, nếu đó là trường hợp, bạn sẽ chỉ cần sửa đổi tập lệnh một chút để lặp qua mảng chứ không chỉ đơn giản là sử dụng mục đầu tiên.

Cuối cùng, cách để giải quyết vấn đề này, là cách giải quyết nhiều vấn đề trong Unix. Phá vỡ nó thành vấn đề dễ dàng hơn. Tìm hoặc viết các công cụ để giải quyết vấn đề dễ dàng hơn. Kết hợp các công cụ đó với vỏ của bạn hoặc các tính năng hệ điều hành khác.

[0] Lưu ý rằng tôi không biết bạn lấy trung tâm chi phí từ đâu, vì vậy tôi mới thực hiện.


tôi đã cài đặt jq trên máy của tôi. nhưng tôi không biết làm thế nào để có được thông tin. tôi đang cập nhật câu hỏi
user3086014

Làm thế nào để làm điều đó. lệnh ec2-description cho phép reslut như thế này. đây là dữ liệu cho 1 thể hiện, có 100 thể hiện. Cách thực hiện điều đó trong một tập lệnh
user3086014

tôi có công cụ aws cli cung cấp cho tôi đầu ra. bây giờ làm thế nào để phân tích đầu ra và các thẻ cần thiết mà tôi thực sự không biết
user3086014

2
@ user3086014 Tôi xin lỗi, nhưng tôi sẽ không đặt nhiều công việc hơn vào câu trả lời này. Hãy xem ví dụ về Ruby tôi có ở đó. Nó sẽ cung cấp cho bạn một nơi tốt để bắt đầu về cách lấy các thẻ ra khỏi các phần khác nhau của JSON mà bạn muốn.
Steven D

Trong số các công cụ json có sẵn, jq là stedolan.github.io/jq/manual yêu thích của tôi . Có sẵn trong phân phối tiêu chuẩn là tốt. Một sân chơi cho các bộ lọc thử nghiệm có sẵn tại jqplay.org/jq?q=.&j=%22Hello%2C%20world!%22
lrkwz

15

Bạn có thể sử dụng tập lệnh python sau để phân tích dữ liệu đó. Giả sử rằng bạn có dữ liệu JSON từ các mảng trong các tệp như array1.json, array2.jsonv.v.

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

Và sau đó chỉ cần chạy:

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

Tôi chưa thấy chi phí trong dữ liệu của bạn, đó là lý do tại sao tôi không bao gồm điều đó.

Theo thảo luận trong các bình luận, tôi đã cập nhật tập lệnh 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"] 

Bạn có thể thử chạy lệnh sau:

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

nhưng đây chỉ là một mảng có các mảng tương tự được trả về bởi lệnh. làm thế nào để làm điều đó
user3086014

và dữ liệu này được tạo bởi lệnh dụ mô tả ec2 khi chạy. Làm thế nào để xử lý việc đó
user3086014

Tôi đã sửa đổi một chút tập lệnh python này: 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() Nếu bạn có tất cả dữ liệu json từ các mảng trong các tệp như Array1.json, Array2.json, ... và cứ thế, bạn có thể thử chạy nó như thế này: # for x in ls * .json; do python parse.py $x; done
Robert Jonczy

bạn có thể tự cập nhật câu trả lời. nó không thể đọc được
user3086014

ngoài ra tôi có mảng.100 mảng như thế này
user3086014

9

Mã jq sau:

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

được sử dụng như:

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

sẽ xuất ra:

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

Một vài gợi ý để hiểu mã:

  • from_entrieslấy một mảng các đối tượng như {key:a, value:b}và biến nó thành một đối tượng với các cặp khóa / giá trị tương ứng ( {a: b});
  • Các phím KeyValuetrong Tagsmảng phải được chuyển đổi thành chữ thường;
  • Chuỗi cuối cùng sử dụng tính năng nội suy chuỗi của jq. Bạn có thể tinh chỉnh nó khi cần thiết.

Để biết thêm chi tiết, hãy xem hướng dẫn và hướng dẫn của jq tại https://stedolan.github.io/jq/


1
Bây giờ bạn có thể rút ngắn việc trích xuất các thẻ bằng cách sử dụng (.Tags | map({Value, Key}) | from_entries) as $tagsmà không cần chuyển đổi khóa thành chữ thường.
mloughran

8

Những người khác đã cung cấp câu trả lời chung cho câu hỏi của bạn, thể hiện những cách tốt để phân tích cú pháp json, tuy nhiên tôi cũng như bạn, đang tìm cách trích xuất id cá thể aws bằng công cụ cốt lõi như awk hoặc sed mà không phụ thuộc vào các gói khác. Để thực hiện điều này, bạn có thể chuyển đối số "--output = text" cho lệnh aws của bạn, nó sẽ cung cấp cho bạn một chuỗi có thể phân tích cú pháp awk. Với điều đó, bạn có thể chỉ cần lấy ID cá thể bằng cách sử dụng một cái gì đó như sau ...

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

3

Jshon có sẵn trong một số bản phân phối:

$ 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

Giải thích nghèo: -e uusẽ trích xuất đối tượng uu, -asẽ làm cho các mảng có thể sử dụng (không chắc chắn tôi một cách chính xác phrased này nhưng dù sao ...), -usẽ giải mã chuỗi, -psẽ quay trở lại mục trước (Có vẻ như -i N, N là số bất kỳ, có tác dụng tương tự) .

Tùy thuộc vào trường hợp của bạn, đầu ra có thể yêu cầu một số xử lý sau (như của bạn, như bạn có thể thấy).

Jshon Mặc dù không có vẻ mạnh mẽ đối với dị tật JSON, mặc dù ("Thẻ" của bạn có dấu phẩy trước dấu ngoặc nhọn đóng sẽ gây ra lỗi).

Ai đó đã đề cập đến jsawk trong một chủ đề khác, nhưng tôi đã không kiểm tra nó.



0

Đây là gợi ý một lớp lót:

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)

Không hoàn hảo, nhưng nó sẽ hoạt động nếu bạn tinh chỉnh nó một chút.

Về cơ bản, nó sử dụng prđể in từng kết quả thiết lập cho mỗi cột. Mỗi tập kết quả được trả về bằng cách thay thế quá trình phân tích tệp JSON và trả về các giá trị dựa trên khóa.

Điều này hoạt động tương tự như được mô tả trong: Cho nội dung khóa-giá trị, làm cách nào để nhóm các giá trị theo khóa và sắp xếp theo giá trị?


0

Hãy xem jtccông cụ cli:

nó cho phép dễ dàng trích xuất thông tin cần thiết từ json của bạn (giả sử nó trong file.json, btw, JSON của bạn cần được sửa chữa, có thêm vài dấu phẩy ở đó):

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

dịch tập tin jason của bạn sang thứ gì đó dễ đọc như thế này:

{
  "phiên bản": [
    "phiên họp",
    1
  ],
  "các cửa sổ": [
    {
      "tab": [
        {
          "mục": [
            {
              "url": "http://orf.at/#/stories/2.../",
              "tiêu đề": "news.ORF.at",
              "bộ ký tự": "UTF-8",
              "ID": 9588,
              "docshellID": 298,
              "Nhà phân tích tài liệu": 10062,
              "kiên trì": đúng
            },
...

Bây giờ có thể phân tích dữ liệu của bạn bằng bất kỳ công cụ tiêu chuẩn nào

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.