Linux에서 쉘 스크립팅으로 JSON을 구문 분석하는 방법은 무엇입니까?


56

Linux에서 몇 가지 매개 변수를 추출 해야하는 JSON 출력이 있습니다.

이것은 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 출력의 특정 값 아래. 여기에 주어진 결과는 단지 예일뿐입니다.

sed과 를 사용하여 어떻게 할 수 awk있습니까?

예상 출력 :

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

1
CLI 호출을 Python으로 파이프하십시오. EC2 인스턴스에 기본이므로 제안되었습니다. 파이썬은 JSON을 쉽게 해석 할 수 있습니다. 예를 보려면 아래 답변을 참조하십시오. 물론 다른 SS 언어도 사용할 수 있지만 Python이 이미 설치되어 있지만 설치가 필요합니다.
Robbie Averill

방법에 대한 노드를 사용하여 ?
Eliran Malka

답변:


65

거의 모든 프로그래밍 언어에서 파서의 가용성은 데이터 교환 형식으로서 JSON의 장점 중 하나입니다.

JSON 파서를 구현하는 대신 jq 와 같은 JSON 구문 분석 용 도구 나 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"]'

수정 된 질문과 의견에 모두 답변하지는 않겠지 만 다음은 귀하가 시작하기에 충분할 것입니다.

STDIN에서 a를 읽고 예제 output [0]의 두 번째 행을 출력 할 수있는 Ruby 스크립트가 있다고 가정하십시오. 이 스크립트는 다음과 같습니다.

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

이제 "Instances"배열에 더 많은 항목이있는 모든 인스턴스에 대해 하나의 json blob을 제공하는 단일 명령이있을 수 있습니다. 그렇다면, 첫 번째 항목을 사용하는 대신 배열을 반복하도록 스크립트를 약간 수정하면됩니다.

결국이 문제를 해결하는 방법은 Unix의 많은 문제를 해결하는 방법입니다. 더 쉬운 문제로 분류하십시오. 보다 쉬운 문제를 해결하기위한 도구를 찾거나 작성하십시오. 해당 도구를 쉘 또는 다른 운영 체제 기능과 결합하십시오.

[0] 비용 센터를 어디에서 구할 수 있을지 모르겠습니다.


내 컴퓨터에 jq를 설치했습니다. 그러나 나는 정보를 얻는 방법을 모른다. 질문을 업데이트하고 있습니다
user3086014

그렇게하는 방법. ec2-describe instance 명령은 이와 같은 reslut를 제공합니다. 이것은 1 개의 인스턴스에 대한 데이터이며 100 개의 인스턴스가 있습니다. 스크립트에서이를 수행하는 방법
user3086014

나에게 출력을주는 AWS CLI 도구가 있습니다. 이제 내가 실제로 모르는 출력 및 필요한 태그를 구문 분석하는 방법
user3086014

2
@ user3086014 죄송하지만이 답변에 더 많은 노력을 기울이지 않을 것입니다. 내가 가지고있는 Ruby 예제를 살펴보십시오. 원하는 JSON의 다양한 부분에서 태그를 얻는 방법을 시작하기에 좋은 장소가 될 것입니다.
Steven D

사용 가능한 json 도구의 수에서 jq는 내가 가장 좋아하는 stedolan.github.io/jq/manual 입니다. 표준 배포에서도 사용할 수 있습니다. 필터 테스트를위한 놀이터는 jqplay.org/jq?q=.&j=%22Hello%2C%20world!
lrkwz

15

다음 파이썬 스크립트를 사용하여 해당 데이터를 구문 분석 할 수 있습니다. 당신은 같은 파일의 배열에서 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-describe instance 명령으로 생성됩니다. 처리 방법
user3086014

이 파이썬 스크립트를 약간 수정했습니다. 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

답변 자체를 업데이트 할 수 있습니다. 읽을 수 없음
user3086014

또한 나는 arrays.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})을 가진 객체로 바꿉니다 .
  • 배열 의 KeyValue키는 Tags소문자로 변환해야했습니다.
  • 마지막 문자열은 jq의 문자열 보간 기능을 사용합니다. 필요에 따라 조정할 수 있습니다.

자세한 내용은 https://stedolan.github.io/jq/ 에서 jq의 자습서 및 설명서를 참조하십시오.


1
(.Tags | map({Value, Key}) | from_entries) as $tags키를 소문자로 변환하지 않고도을 사용하여 태그 추출을 단축 할 수 있습니다 .
mloughran

8

다른 사람들은 json을 파싱하는 좋은 방법을 보여주는 일반적인 답변을 제공했지만 다른 패키지에 의존하지 않고 awk 또는 sed와 같은 핵심 도구를 사용하여 AWS 인스턴스 ID를 추출하는 방법을 찾고있었습니다. 이를 위해 aws 명령에 "--output = text"인수를 전달하면 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 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 파일을 구문 분석하고 키를 기반으로 값을 리턴하는 프로세스 대체에 의해 리턴됩니다.

:에 설명 된대로이 유사한 작동 을 감안할 때 키 - 값의 내용, 수행하는 방법 키에 의해 정렬 값을 기준으로 I 그룹 값?


0

jtccli 도구를 살펴보십시오 .

json에서 필요한 정보를 쉽게 추출 할 수 있습니다 (이것이 file.jsonbtw이고 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,
              "지속 자": true
            },
...

이제 표준 도구로 데이터를 구문 분석 할 수 있어야합니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.